So I'm following a react tutorial and in that project material-ui is being used, it's e-commerce, so I have Products.jsx and Product.jsx files.
Product.jsx file:
import React from 'react';
import { Card, CardMedia, CardContent, CardActions, Typography, IconButton} from '#material-ui/core';
import { AddShoppingCart } from '#material-ui/icons';
import MuiThemeProvider from '#material-ui/core/styles/MuiThemeProvider';
const Product = ( {product} ) => {
return (
<MuiThemeProvider>
<Card className="rootie">
<CardMedia className="media" image='' title={product.name} />
<CardContent>
<div className="cardContent">
<Typography variant="h5" gutterBottom>
{product.name}
</Typography>
<Typography variant="h5" gutterBottom>
{product.price}
</Typography>
</div>
<Typography variant="h2" color="textSecondary">{product.description}</Typography>
</CardContent>
<CardActions disableSpacing className="cardActions">
<IconButton aria-label="Add to cart">
<AddShoppingCart/>
</IconButton>
</CardActions>
</Card>
</MuiThemeProvider>
);
}
export default Product;
Products.jsx:
import React from 'react';
import { Grid } from '#material-ui/core';
import Product from '../Product/Product';
import MuiThemeProvider from '#material-ui/core/styles/MuiThemeProvider';
const products = [
{ id: 1, name: 'JBL', description: 'JBL', price: '$100'},
{ id: 2, name: 'AirPods', description: 'AirPods', price: '$100'},
];
const Products = () => {
return (
<MuiThemeProvider>
<Grid container justifyContent="center" spacing={4}>
{products.map((product) =>{
<Grid item key={product.id} xs={12} sm={6} md={4} lg={3}>
<Product product={product}/>
</Grid>
})}
</Grid>
</MuiThemeProvider>
);
}
export default Products;
And my App.js looks like this:
import React from 'react';
import Header from './components/Header/Header';
import Products from './components/Products/Products';
import './App.scss';
const App = () => {
return (
<div>
<Products/>
</div>
)
}
export default App;
So as you see, everything looks okay, but for some reason React doesn't render the components, so the page looks empty. I've searched on the internet and found about 'MuiThemeProvider', but adding it didn't really help either.
You need to create a theme and pass it as prop to ThemeProvider which in turn wraps the entire App during ReactDOM.render stage itself. Something like this:
import * as React from 'react';
import ReactDOM from 'react-dom';
import CssBaseline from '#mui/material/CssBaseline';
import { ThemeProvider } from '#mui/material/styles';
import App from './App';
import theme from './theme';
ReactDOM.render(
<ThemeProvider theme={theme}>
{/* CssBaseline kickstart an elegant, consistent, and simple baseline to build upon. */}
<CssBaseline />
<App />
</ThemeProvider>,
document.querySelector('#root'),
);
Only then will your Material UI components work as you expect.
Related
i am creating a react movie app that uses an movie app API from rapid API. on home page everything is working perfectly and I am able to render all movies in the form of cards. i have set the app in such a way that when user clicks on movie card it should direct to Moviedetail page. for this i am using react-router-dom and everything is set up right. on clicking movie card it does navigate to Moviedetail page but nothing is being rendered and getting this error in browser console.
(Uncaught TypeError: Cannot read properties of undefined (reading 'length')
at Details (Details.js:18:1));
but if i comment Detail and MovieTrailers component in MovieDetails page and uncomment it then everything on MovieDetails page is rendered perfectly. again if i refresh the page it breaks again and i get the same browser console error.
import React, {useState, useEffect} from "react";
import {Box} from "#mui/material";
import {useParams} from "react-router-dom";
import MovieTrailers from "../components/MovieTrailers";
import Details from "../components/Details";
import {fetchData, options} from "../utils/fetchData";
function MovieDetails() {
const [movieDetailData, setMovieDetailData] = useState({});
const [movieTrailerData, setMovieTrailerData] = useState([]);
const {id} = useParams();
// console.log(id);
console.log(movieDetailData);
console.log(movieTrailerData);
useEffect(()=>{
const fetchMovieData = async ()=> {
const detailData = await fetchData(`https://movies-app1.p.rapidapi.com/api/movie/${id}`, options);
setMovieDetailData(detailData.result);
const trailerData = await fetchData(`https://movies-app1.p.rapidapi.com/api/trailers/${id}`, options);
setMovieTrailerData(trailerData.result);
}
fetchMovieData();
},[id]);
return(
<Box>
<Details
movieDetailData={movieDetailData}
/>
<MovieTrailers
movieTrailerData={movieTrailerData}
/>
</Box>)
}
export default MovieDetails;
////here is Details component
import React from "react";
import {Box, Stack, Typography, Chip} from "#mui/material";
function Details(props) {
const{image, titleOriginal, countries, genres, rating, release, description} = props.movieDetailData;
return <Stack direction="row" width="100%" sx={{backgroundColor:"#fff"}}>
<img className="movie-poster" src={image} alt="movie-poster"/>
<Stack p="50px" sx={{width:"60%"}}>
<Typography variant="h2" fontWeight="700">
{titleOriginal}
</Typography>
<Box pt="30px" sx={{display:"flex", gap:"30px"}}>
<Chip label={<Typography variant="h6" fontWeight="700">{`rating : ${rating}`}</Typography>} />
<Chip label={<Typography variant="h6" fontWeight="700">{`release: ${release}`}</Typography>} />
</Box>
<Typography variant="h6" pt="30px">
{description.length>600 ? description.substring(0, 601) : description}
</Typography>
<Box pt="30px" sx={{display:"flex", gap:"30px"}}>
<Chip label={<Typography variant="h6" fontWeight="700">{`genre : ${genres[0].name}`}</Typography>} />
<Chip label={<Typography variant="h6" fontWeight="700">{`origin : ${countries[0].name}`}</Typography>} />
</Box>
</Stack>
</Stack>
}
export default Details;
////here is MovieTrailer component
import React from "react";
import {Box, Stack, Typography} from "#mui/material";
import TrailerCard from "./TrailerCard";
import {nanoid} from "nanoid";
function MovieTrailers({movieTrailerData}) {
console.log(movieTrailerData);
return <Box p="30px">
<Typography variant="h4" pt="40px" pb="50px" fontWeight="700" m="auto">{`Watch ${movieTrailerData[0].title}`}
</Typography>
<Stack direction="row" justifyContent="space-between">
{(movieTrailerData.slice(0, 3)).map((trailer)=>(
<TrailerCard trailer={trailer}/>
))}
</Stack>
</Box>
}
export default MovieTrailers;
////here is TrailerCard component
import React from "react";
import {Box, Stack, Typography, Chip} from "#mui/material";
function TrailerCard({trailer}) {
const{thumbnail, ago, author, views, title, url, description} = trailer;
return <Box className="trailer-card" p="10px" backgroundColor="#fff" width="25%">
<Stack>
<a
className="movie-trailer-link"
href={url}
target="_blank"
rel="noreferrer">
<img className="movie-trailer-thumbnail" src={thumbnail} alt="movie-trailer"/>
<Typography pt="10px" variant="body1" fontWeight="700" >
{title}
</Typography>
<Stack paddingBlock="10px" direction="row" justifyContent="space-between" gap="10px" flexWrap="wrap">
<Chip label={`views: ${views}`} />
<Chip label={`ago: ${ago}`}/>
</Stack>
<Typography variant="subtitle2">{`YT: ${author.name}`}</Typography>
<Typography variant="body2" pb="20px">
{description}
</Typography>
</a>
</Stack>
</Box>
}
export default TrailerCard;
In your movie detail component, add a loading state initially set to true. Upon resolution of the API call in the useEffect, set the loading variable to false.
In the jsx, render the page data if loading is false else show a loader or something else
movieDetailData is an empty object before you fetch your data from backend. That's why you get an error.
First check if your props has suitable keys.
import React from "react";
import {Box, Stack, Typography, Chip} from "#mui/material";
function Details(props) {
if (Object.keys(props.movieDetailData).length == 0)
return null;
const{image, titleOriginal, countries, genres, rating, release, description} = props.movieDetailData;
// rest of your code
}
I'm trying to make a react app that loads a google map.
but somehow the map doesn't show and not an error was reported in console logs....
import React from 'react'
import GoogleMapReact from 'google-map-react'
import {Paper, Typography, useMediaQuery} from '#material-ui/core'
import LocationOnOutlinedIcon from '#material-ui/icons/LocationOnOutlined'
import Rating from '#material-ui/lab'
import useStyles from './styles'
const Map = () => {
const classes = useStyles()
const isMobile = useMediaQuery('(min-width:600px)')
const coordinates = { lat:0, lng: 0}
return (
<div className={classes.mapContainer}>
<GoogleMapReact
bootstrapURLKeys={{ key: 'AIzaSyBrSAzFufdmJBVojpd7idemPVGp8HskFKY' }}
defaultCenter={coordinates}
center={coordinates}
defaultZoom={14}
margin={[50,50,50,50]}
>
</GoogleMapReact>
</div>
)
}
export default Map
ㄴ this is Map.js file
import Header from "./components/Header/Header";
import {List} from "./components/List/List";
import Map from "./components/Map/Map";
import {CssBaseline, Grid} from '#material-ui/core';
function App() {
return (
<div className="App">
<CssBaseline></CssBaseline>
<Header/>
<Grid container spacing={3} style={{ width: '100%'}}>
<Grid item xs={12} md={4}>
<List/>
</Grid>
<Grid item xs={12} md={8}>
<Map/>
</Grid>
</Grid>
</div>
);
}
export default App;
ㄴthis is App.js file
enter image description here
What's causing the error(if that is an error)?
j
How can I make the map show up in my app?
useState not working. I have searched for a solution I checked many forms like https://github.com/vercel/next.js/issues/7626 , https://github.com/vercel/next.js/issues/17592 ,
Hooks error: Invalid Hook Call using NextJS or ReactJS on Windows , some people seem to suggest that it can be solved by removing a node module that they did not mention the name of, others says it works if they change their webpack configurations but i have never used webpack and couldn't find they mentioned so I am stuck.
I was implementing material ui's drawer, i have created a drawer component and imported it.
Nav.jsx:
import React, { useState } from 'React'
import SignedOutLinks from "./Links/SignedOutLinks"
import { AppBar, Toolbar } from "#material-ui/core"
import MenuBtn from "./Links/MenuBtn"
import Logo from "./Links/Logo"
import CategoryBtn from "./Links/CategoryBtn"
import ShoppingCartBtn from "./Links/ShoppingCartBtn"
import LanguageBtn from "./Links/LanguageBtn"
import DarkModeBtn from "./Links/DarkModeBtn"
import NotificationBtn from "./Links/NotificationBtn"
import SignedIn from "./Links/SignedIn"
import Grid from '#material-ui/core/Grid';
import Search from "./Search/Search"
import { useTheme } from '#material-ui/core/styles';
import useMediaQuery from '#material-ui/core/useMediaQuery';
import Drawer from './Drawer/Drawer'
const signedIn = true
const Nav = () => {
const [isOpened, setIsOpened] = useState(false)
const theme = useTheme()
const isMobile = useMediaQuery(theme.breakpoints.down("sm"))
const handleDrawerToggle = () => {
setIsOpened(!isOpened)
}
return (
<AppBar color="transparent" elevation={0} >
<Toolbar>
{
!isMobile?
<Grid
container
direction="row"
justify="space-between"
alignItems="center"
spacing={10}
>
<Grid item container spacing={5} xs={4} justify="flex-start" wrap="nowrap">
<Grid item>
<Logo/>
</Grid>
<Grid item>
<CategoryBtn />
</Grid>
</Grid>
<Grid item xs={4}>
<Search />
</Grid>
<Grid item container xs={4} justify="flex-end" wrap="nowrap">
<ShoppingCartBtn />
<LanguageBtn />
<DarkModeBtn />
<NotificationBtn />
{signedIn? <SignedIn /> : <SignedOutLinks />}
</Grid>
</Grid>
:
<div>
<Drawer isOpened={isOpened} />
<Grid
container
direction="row"
justify="space-around"
spacing={10}
>
<Grid item container xs={4} justify="flex-start">
<MenuBtn handleClick={handleDrawerToggle} />
</Grid>
<Grid item Container xs={4} justify="center" style={{textAlign: "center"}}>
<Grid item>
<Logo />
</Grid>
</Grid>
<Grid item container xs={4} justify="flex-end">
<ShoppingCartBtn />
</Grid>
</Grid>
</div>
}
</Toolbar>
</AppBar>
)
}
export default Nav
Drawer.jsx:
import { Drawer as MUIDrawer} from '#material-ui/core'
import { List, ListItem,ListItemText, ListItemIcon } from '#material-ui/core'
import NotificationsIcon from '#material-ui/icons/Notifications';
import TranslateIcon from '#material-ui/icons/Translate';
import Brightness4Icon from '#material-ui/icons/Brightness4';
import LocalShippingIcon from '#material-ui/icons/LocalShipping';
import AccountCircleIcon from '#material-ui/icons/AccountCircle';
import BusinessIcon from '#material-ui/icons/Business';
import ExitToAppIcon from '#material-ui/icons/ExitToApp';
import ChatBubbleOutlineIcon from '#material-ui/icons/ChatBubbleOutline';
import CategoryIcon from '#material-ui/icons/Category';
function Drawer({isOpened}) {
const items = [
{
text: user.userName,
icon: <AccountCircleIcon />
},
{
text: "Categories",
icon: <CategoryIcon />
},
{
text: "Language",
icon: <TranslateIcon />
},
{
text: "Mode",
icon: <Brightness4Icon />
},
{
text: "Notifications",
icon: <NotificationsIcon />
},
{
text: "Orders",
icon: <LocalShippingIcon />
},
{
text: "Are You a Seller?",
icon: <BusinessIcon />
},
{
text: "Messages",
icon: <ChatBubbleOutlineIcon />
},
{
text: "Logout",
icon: <ExitToAppIcon />
}
]
return (
<div>
<MUIDrawer open={isOpened}>
<List>
{
items.map(item => {
return (
<ListItem button key={item.text} >
{item.icon && <ListItemIcon>{item.icon}</ListItemIcon>}
<ListItemText primary={item.text} />
</ListItem>
)
})
}
</List>
</MUIDrawer>
</div>
)
}
export default Drawer
Note it was working fine until i coded the Drawer, also useState is imported at the very beginning ing so i didn't forget to import it
Edit:
Folder Structure in next.js
index.js:
import Head from 'next/head'
import styles from '../styles/Home.module.css'
import Nav from '../Components/Navbar/Nav'
export default function Home() {
return (
<>
<Head>
<meta name="description" content="Everything for everyone. TRNC E-commerce website focused on a huge variety of categories from fashion to electronics. Order now and get your product delivered." />
</Head>
<div className={styles.container}>
<Nav />
</div>
</>
)
}
Its finally working, however I couldn't find the problem. I solved it by literaly creating a new component called Nav2 that i copied the same code from the original Nav component from and voila it worked, i deleted the old Nav component and renamed Nav2 to Nav and it kept working.
Note: i found that i forgot to import useContext in the drawer as user is an deconstructed object that is sent from _app.js so i added
const { user } = useContext(UserContext)
to the beginning of the component function
I'm integrating Material-UI (v4.4.3) into a React (v16.9.2) TypeScript (v3.6.3) website. Using the sample AppBar component example https://material-ui.com/components/app-bar/ and the TypeScript Guide https://material-ui.com/guides/typescript/#typescript I have the following functional component.
However, I'm getting a TS error for useStyles() on this line
const classes = useStyles();
(TS): Expected one argument, but got 0.
import * as React from 'react';
import { createStyles, Theme, makeStyles } from '#material-ui/core/styles';
import AppBar from '#material-ui/core/AppBar';
import Toolbar from '#material-ui/core/Toolbar';
import Typography from '#material-ui/core/Typography';
import Button from '#material-ui/core/Button';
import IconButton from '#material-ui/core/IconButton';
import MenuIcon from '#material-ui/icons/Menu';
const useStyles = makeStyles(({ spacing }: Theme) =>
createStyles({
root: {
flexGrow: 1,
},
menuButton: {
marginRight: spacing(2),
},
title: {
flexGrow: 1,
},
}),
);
export default function ButtonAppBar() {
const classes = useStyles();
return (
<div className={classes.root}>
<AppBar position="static">
<Toolbar>
<IconButton edge="start" className={classes.menuButton} color="inherit" aria-label="menu">
<MenuIcon />
</IconButton>
<Typography variant="h6" className={classes.title}>
MSC
</Typography>
<Button color="inherit">Login</Button>
)}
</Toolbar>
</AppBar>
</div>
);
}
I want to use the default theme. Am I missing something?
Try to pass an empty object:
const classes = useStyles({});
try using components from :
import AppBar from "#material-ui/core/AppBar"
import XXX from "#material-ui/core/xxx"
XXX = other components
notes my dependencies are:
dependencies : "#material-ui/core": "^4.9.14"
devDependencies : "#types/material-ui": "^0.21.7"
don't forgot to import #types/material-ui devDependencies in your project.
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.