Errors when using the CardContent component in Material UI beta - reactjs

I am attempting to migrate from the previous version of Material UI to the new beta, however this error is driving me mad.
To put it simply, this works fine with no errors:
const Setup = () => {
return (
<div style={{ margin: '20px' }}>
<Card>
<CardHeader title="Let's get set up." />
</Card>
</div>
);
};
export default Setup;
But this does not:
const Setup = () => {
return (
<div style={{ margin: '20px' }}>
<Card>
<CardHeader title="Let's get set up." />
<CardContent>
</CardContent>
</Card>
</div>
);
};
export default Setup;
Here are the errors produced:

Thanks to Devang Naghera for pointing this out.
I noticed that CardContent is undefined, even though I import it at the top of my file with
import Card, { CardHeader, CardContent } from 'material-ui/Card';
A workaround seems to be to change my imports to
import Card, { CardHeader } from 'material-ui/Card';
import CardContent from 'material-ui/Card/CardContent';
The code works now.
Edit:
It turns out this issue was being caused by some files left over from an older version of MUI. I deleted node-modules and redownloaded dependencies, which fixed the issue for me.

Related

How to link external url with button in Material UI?

I'm pretty new to Material-UI and testing my web-app with localhost. Basically, I have created a button that will route to external url (www.google.ca for now) when the user clicks on it. For unknown reason, clicking a button routes to http://localhost:3001/www.google.ca instead of https://www.google.ca. Not sure what the problem is?
import React from 'react';
import { makeStyles } from '#material-ui/core/styles';
import Card from '#material-ui/core/Card';
import CardActionArea from '#material-ui/core/CardActionArea';
import CardActions from '#material-ui/core/CardActions';
import CardContent from '#material-ui/core/CardContent';
import CardMedia from '#material-ui/core/CardMedia';
import Button from '#material-ui/core/Button';
import Typography from '#material-ui/core/Typography';
import Link from '#material-ui/core/Link';
import waterBottle from '../images/tom.jpg';
// All the code has been retrieved from https://material-ui.com/components/cards/#card
const useStyles = makeStyles({
root: {
maxWidth: 345,
},
media: {
height: 140,
},
});
export default function MembersInfo() {
const classes = useStyles();
return (
<Card className={classes.root}>
<CardActionArea>
<CardMedia
className={classes.media}
image={waterBottle}
title="Image"
/>
<CardContent>
<Typography gutterBottom variant="h5" component="h2">
Tom Wong
</Typography>
<Typography variant="body2" color="textSecondary" component="p">
Tom is a business administrative student at xxx university.
</Typography>
</CardContent>
</CardActionArea>
<CardActions>
<Button size="small" color="primary" href="www.google.ca" target="_blank" to = "/url">
Google
</Button>
</CardActions>
</Card>
);
}
In case anyone runs across this issue with using the Link component from Material UI - a few comments addressed some of the issues.
Additionally, make sure you're importing the Link correctly from material ui since they've updated their API. I tried using the API provided ('#mui/material/Link') but had to use their old API (#material-ui/core/Link) for it to work.
If the import is correct, this is the the code that will open up a new tab to google while you're developing using localhost:
<Link target="_blank" href="http://www.google.com" rel="noreferrer">
View Link
</Link>

Infinite Scroll using Algolia on React

I'm trying to implement infinite scrolling on my react app for search hits from Algolia.
I came across a class component in their documentation. And I use React Hooks so tried to make it work on React Hooks. All I got was so many renders and my app gets hung up when this component mounts.
Here's my code:
import React, { useEffect, useRef } from 'react';
import Card from '#material-ui/core/Card';
import CardActionArea from '#material-ui/core/CardActionArea';
import CardActions from '#material-ui/core/CardActions';
import CardContent from '#material-ui/core/CardContent';
import CardMedia from '#material-ui/core/CardMedia';
import Button from '#material-ui/core/Button';
import IconButton from '#material-ui/core/IconButton';
import Typography from '#material-ui/core/Typography';
import Container from '#material-ui/core/Container';
import Grid from '#material-ui/core/Grid';
import { connectHits, connectInfiniteHits } from 'react-instantsearch-dom';
import noItemImage from './../../assets/img/noItemImage.png'
import { Link } from 'react-router-dom'
import ShareIcon from '#material-ui/icons/Share';
import PropTypes from 'prop-types';
function AlgoliaHits(props) {
const { hits } = props
console.log(hits)
var sentinel = useRef(null)
useEffect(() => {
function onSentinelIntersection (entries){
const { hasMore, refine } = props
entries.forEach(entry => {
if (entry.isIntersecting && hasMore) {
refine()
}
})
}
var observer = new IntersectionObserver(onSentinelIntersection, {})
observer.observe(sentinel.current)
return () => {
observer.disconnect()
}
}, [props])
return (
<Container maxWidth="md" style={{ marginBottom: 100 }}>
<Grid container spacing={2}>
{
hits.map(hit => (
<Grid item xs={12} sm={6} md={4} lg={4} xl={3}>
<Link to={`/item/${hit.item_id}`} style={{ textDecoration: 'none' }}>
<Card maxWidth={210} key={hit.item_id} elevation={0}>
<CardActionArea>
<CardMedia
component="img"
alt="Contemplative Reptile"
height="140"
image={
hit.item_images_url ?
hit.item_images_url.length === 0 ?
noItemImage
:
hit.item_images_url[0]
:
noItemImage
}
title={hit.item_name}
/>
<CardContent>
<Typography gutterBottom variant="h5" component="h2"
style={{ whiteSpace: 'nowrap', width: 250, overflow: 'hidden', textOverflow: 'ellipsis' }}>
{hit.item_name}
</Typography>
<Typography variant="body2" color="textSecondary" component="p"
style={{ whiteSpace: 'nowrap', width: 200, overflow: 'hidden', textOverflow: 'ellipsis' }}>
{hit.item_description}
</Typography>
</CardContent>
</CardActionArea>
<CardActions>
<Button size="small" color="primary" component={Link} to={`/item/${hit.item_id}`}>
View
</Button>
<IconButton size="small" color="secondary">
<ShareIcon style={{ padding: 4 }}/>
</IconButton>
</CardActions>
</Card>
</Link>
</Grid>
))
}
</Grid>
<div id="sentinel" ref={sentinel} />
</Container>
);
}
AlgoliaHits.propTypes = {
hits: PropTypes.arrayOf(PropTypes.object).isRequired,
hasMore: PropTypes.bool.isRequired,
refine: PropTypes.func.isRequired,
}
const AlgoliaInfiniteScroll = connectHits(AlgoliaHits)
const ItemCard = connectInfiniteHits(AlgoliaInfiniteScroll)
export default ItemCard
And here's where I used the reference from. What wrong am I doing? And how to solve it?
TIA
My first thought here is that the issue may be in the useEffect dependency array.
The useEffect hook will trigger whenever one of it's dependencies changes. In your case, you've specified the dependency array as [props], meaning every time a prop changes, it will trigger once more. As props likely changes quite often, for objects such as props.hits, I'd wager this is throwing your code into the infinite loops you mention.
I believe in the original example, the onSentinelIntersection functionality only occurs once, when the component mounts.
I'd start with an empty dependency array: [] at the end of your useEffect. This is a (albeit a little bit hacky) way to replace componentDidMount and only run once, when the component's first render.
If that helps, you may be most of the way there. I would also recommend, however, moving the onSentinelIntersection function out of the useEffect (or even completely out of the component, if possible!) - as it's good practice to keep as much code outside of a useEffect as possible (as it'll be evaluated every time it executes).
So something like:
function AlgoliaHits(props) {
const { hits } = props
console.log(hits)
var sentinel = useRef(null)
function onSentinelIntersection (entries){
const { hasMore, refine } = props
entries.forEach(entry => {
if (entry.isIntersecting && hasMore) {
refine()
}
})
}
useEffect(() => {
var observer = new IntersectionObserver(onSentinelIntersection, {})
observer.observe(sentinel.current)
return () => observer.disconnect()
}, [])
....
May be a good start. You may be able to safely add [IntersectionObserver, onSentinelIntersection] to the useEffect dependencies too, as they're technically required for the useEffect to function, and shouldn't cause any further triggers of useEffect in this case.
The Dependencies & Performance section of the React useEffect docs is helpful here- as well as the whole page itself.
For extra resources, I really got a lot of mileage out of The Complete Guide To useEffect by Dan Abramov - Long read, but worth it, I think (when you have the time, that is!)

Material UI upload button showing no file chosen

I am trying to use one of the MU upload buttons with ReactJS, with the exact code from the official page (4th button, with the icon): https://material-ui.com/components/buttons/#upload-button
I've imported all the needed dependencies, and my React code for this button is as follows:
import { makeStyles } from "#material-ui/core/styles";
import Button from "#material-ui/core/Button";
import IconButton from "#material-ui/core/IconButton";
import PhotoCamera from "#material-ui/icons/PhotoCamera";
import "./SignUp.css";
const useStyles = makeStyles(theme => ({
root: {
"& > *": {
margin: theme.spacing(1)
}
}
}));
function SignUp() {
const classes = useStyles();
return (
<label htmlFor="icon-button-file">
<IconButton
color="primary"
aria-label="upload picture"
component="span"
>
<PhotoCamera />
</IconButton>
</label>
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
However I'm seeing this fairly ugly "Choose file" - no file chosen button. I should only be seeing the camera icon at the bottom.
enter image description here
Could anyone point me in the right direction?
I found the issue. I had forgotten to add this piece of code:
input: {
display: "none"
}
This goes into the useStyles function.
This might help you Link in same way.
import React from "react";
import "./styles.css";
import IconButton from "#material-ui/core/IconButton";
import PhotoCamera from "#material-ui/icons/PhotoCamera";
export default function App() {
return (
<div className="App">
<IconButton>
<PhotoCamera />
</IconButton>
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
</div>
);
}

Problem with showing a component which is in another file onclick

I am currently building an website in React with a navigation bar which I use Material-UI for.
My problem is that when I for example click "About" in my navigation bar, I want to show the content/component in About, and when I click Home I want the component Home to be shown and others hidden.
The problem is I am still a beginner in React and want to practice my React skills and now I have the navbar, Home, About in seperate files and not sure on how to pass through state, props and so in this case.
I will show a screen shot on the website and code-snippets to show my code so far.
My website:
File structure of my program:
Here is Code:
App.js:
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import NavBar from './Components/Navigationbar'
import Home from './Components/Home'
import About from './Components/About'
class App extends Component {
constructor(props){
super(props);
this.state = {showAbout: true};
this.handleAbout = this.handleAbout.bind(this);
}
handleAbout(){
this.setState({showAbout: true})
}
render() {
return (
<div className="App">
<div className="App-header">
</div>
<NavBar></NavBar>
<p className="App-intro">
<Home></Home>
</p>
{this.state.showAbout ? <About /> : null}
</div>
);
}
}
export default App;
Home.jsx:
import React from 'react';
import { makeStyles } from '#material-ui/core/styles';
import Paper from '#material-ui/core/Paper';
import Typography from '#material-ui/core/Typography';
const useStyles = makeStyles(theme => ({
root: {
padding: theme.spacing(3, 2),
backgroundColor: 'mistyrose'
},
}));
export default function PaperSheet() {
const classes = useStyles();
return (
<div>
<Paper className={classes.root}>
<Typography variant="h5" component="h3">
Home
</Typography>
<Typography component="p">
Welcome Home
</Typography>
</Paper>
</div>
);
}
About.jsx:
import React from 'react';
import { makeStyles } from '#material-ui/core/styles';
import Paper from '#material-ui/core/Paper';
import Typography from '#material-ui/core/Typography';
const useStyles = makeStyles(theme => ({
root: {
padding: theme.spacing(3, 2),
backgroundColor: 'mistyrose'
},
}));
export default function PaperSheet() {
const classes = useStyles();
return (
<div>
<Paper className={classes.root}>
<Typography variant="h5" component="h3">
About
</Typography>
<Typography component="p">
About
</Typography>
</Paper>
</div>
);
}
And finally the navigation bar which is from Material UI:
Navigationbar.jsx:
import React from 'react';
import ReactDOM from 'react-dom';
import Button from '#material-ui/core/Button';
import App from '../App';
import { makeStyles } from '#material-ui/core/styles';
import Paper from '#material-ui/core/Paper';
import Tabs from '#material-ui/core/Tabs';
import Tab from '#material-ui/core/Tab';
import About from './About';
const useStyles = makeStyles({
root: {
flexGrow: 1,
},
});
function handleAbout(props){
alert('About');
}
const navBar = (props) => {
return (
<Paper >
<Tabs
//value={value}
onChange={handleChange}
indicatorColor="primary"
textColor="primary"
centered
>
<Tab label="Home" />
<Tab label="About" onClick={() => handleAbout(props)} />
<Tab label="Contact" />
</Tabs>
</Paper>
);
}
//ReactDOM.render(<navBar />, document.querySelector('#app'));
export default navBar;
My problem is I want to when I click "About" in the navbar, I want to show the About component(the content in About.jsx) on my website but not sure on how to handle state and props in the case when they are in seperate files.
Would appreciate if someone could help me.
Thanks a lot.
You can use react-router for navigation. How to install and use it is quite nicely shown on the page: https://reacttraining.com/react-router/web/guides/quick-start
Oh boy, this is a big one...
In the simplest case, you pass state though props like this:
<ChildComponent showAbout={this.state.showAbout}/>, and access it in ChildComponent by props.showAbout (or this.props.showAbout if it's a class component).
But things can get complicated as your application scales. Values can only be passed through props downwards inside the component tree; in other words, a component can only see a state that's somewhere above it. You can't use state from a sibling component or a component below it.
And that's the whole reason state management libraries exist. They provide a 'global' state that is available anywhere in the app. Redux is one of them.
You should sit down and learn Redux, as you can't really make a big app without a state management tool.
Another thing you should learn is react-router, for client-side routing.
Those things combined will provide a powerful tool for making useful apps.

Importing Ant Design Component doesn't work

I'm shocked over this problem I'm currently having right now. All my logic literally stopped. Something started not working, without me having changed anything. I mean I even have it on production, the identical code, but locally it started not working, out of nothing. Even when I go back to previous commits, that I'm 100% sure was working, it doesn't work.
Meteor, React, Ant-Design. Please help!
The error is: ReferenceError: Layout is not defined
Code is:
import React from 'react';
import Blaze from 'meteor/gadicc:blaze-react-component';
import { Link } from 'react-router-dom';
import { Layout, Menu } from 'antd';
const { Header, Content, Footer } = Layout;
class LayoutContainer extends React.Component {
render() {
const { match, children } = this.props;
const pathname = match.location.pathname;
return (
<Layout className="layout">
<Header style={{backgroundColor: '#fff'}}>
<Menu
selectedKeys={[pathname]}
mode="horizontal"
style={{ lineHeight: '64px', float: 'right' }}
>
<Menu.Item key={'/'}>
<Link to="/">Home</Link>
</Menu.Item>
<Menu.Item key={'/create-a-gathering'}>
<Link to="/create-a-gathering">Create</Link>
</Menu.Item>
</Menu>
<div className="logo" />
<Blaze template="loginButtons" />
</Header>
<Content style={{ marginTop: 20 }}>
{children}
</Content>
<Footer style={{ textAlign: 'center' }}>
</Footer>
</Layout>
)
}
}
export default LayoutContainer;
this is a reported antd issue here Reference Error: Layout not defined
an easy way to solve this is importing layout like this
import Layout from 'antd/lib/layout'
or you can also sort it out by updating antd version to "^3.2.2" or up
I should have answered this long time ago, but here it goes:
As Afaq Ahmed Khan pointed out (that too) :
import { Layout, Menu } from 'antd/lib';
is the answer.
I guess babel in two packages conflict with each other and thus '/lib' to root '/' alias doesn't work.
That can be resolved by deleting node-modules folder then rebuilding the whole project.

Resources