I am getting this error message in console (Uncaught TypeError: setCurrentId is not a function
at onClick (Post.js:19:1) )
I don't know how to handle this error
This is Child Component Post.js
import { Button, Card,CardActions,CardContent,CardMedia,Typography } from '#material-ui/core';
import React from 'react';
import useStyles from "./styles";
import MoreHorizIcon from '#mui/icons-material/MoreHoriz';
import DeleteIcon from '#mui/icons-material/Delete';
import ThumbUpAltIcon from '#mui/icons-material/ThumbUpAlt';
import moment from 'moment';
const Post= ({post , setCurrentId})=>{
const classes = useStyles();
return(
<Card className={classes.card}>
<CardMedia className={classes.media} image={post.selectedFile} title={post.title}/>
<div className={classes.overlay}>
<Typography variant='h6'>{post.creator}</Typography>
<Typography variant='body2'>{moment(post.createdAt).fromNow()}</Typography>
</div>
<div className={classes.overlay2}>
<Button style={{ color: 'white' }} size="small" onClick={() => setCurrentId(post._id)}><MoreHorizIcon fontSize="default" /></Button>
</div>
<div className={classes.details}>
<Typography variant='body2' color='textSecondary'>{post.tags.map((tag)=>`#${tag} `)}</Typography>
</div>
<CardContent>
<Typography className={classes.title} variant='h5' gutterBottom>{post.message}</Typography>
</CardContent>
<CardActions className={classes.cardActions}>
<Button size = 'small' color='primary' onClick={()=>{}}>
<ThumbUpAltIcon fontSize='small'/>
Like
{post.likeCount}
</Button>
<Button size = 'small' color='primary' onClick={()=>{}}>
<DeleteIcon fontSize='small'/>
Delete
</Button>
</CardActions>
</Card>
)
}
export default Post;
This is parent Component
import React from 'react';
import { Grid, CircularProgress } from '#material-ui/core';
import { useSelector } from 'react-redux';
import Post from './Post/Post';
import useStyles from './styles';
const Posts = ({ setCurrentId }) => {
const posts = useSelector((state) => state.posts);
const classes = useStyles();
return (
!posts.length ? <CircularProgress /> : (
<Grid className={classes.container} container alignItems="stretch" spacing={3}>
{posts.map((post) => (
<Grid key={post._id} item xs={12} sm={6} md={6}>
<Post post={post} setCurrentId={setCurrentId} />
</Grid>
))}
</Grid>
)
);
};
This is main file App.js
import React, { useState, useEffect } from 'react';
import { Container, AppBar, Typography, Grow, Grid } from '#material-ui/core';
import { useDispatch } from 'react-redux';
import Posts from './components/Posts/Posts';
import Form from './components/Form/Form';
import { getPosts } from './actions/posts';
import useStyles from './styles';
import memories from './images/memories.png';
const App = () => {
const [currentId, setCurrentId] = useState(0);
const dispatch = useDispatch();
const classes = useStyles();
useEffect(() => {
dispatch(getPosts());
}, [currentId, dispatch]);
return (
<Container maxWidth="lg">
<AppBar className={classes.appBar} position="static" color="inherit">
<Typography className={classes.heading} variant="h2" align="center">Memories</Typography>
<img className={classes.image} src={memories} alt="icon" height="60" />
</AppBar>
<Grow in>
<Container>
<Grid container justify="space-between" alignItems="stretch" spacing={3}>
<Grid item xs={12} sm={7}>
<Posts setCurrentId={setCurrentId} />
</Grid>
<Grid item xs={12} sm={4}>
<Form currentId={currentId} setCurrentId={setCurrentId} />
</Grid>
</Grid>
</Container>
</Grow>
</Container>
);
};
export default App;
I am trying to debug my react code and expecting something that I missed
Related
I am using Formik in order to submit an array of components using MUI sliders.
I have created a slider component using the MUI library. You can see that in the code below in the declaration of:
import SliderSchedule from ....
So, I searched an example and I found a way to create and delete components and I copy from them. However now I want to also submit the result. But when I click the button I get no values.
As you can see I have the Comp1 that I declare the array const [sliderSchedule, setSliderSchedule]. Which has to contain values like: [(100, 200), (150, 300), (400, 700), ...].
Then I have the two function addHandeler and deleteHandeler that creates and deletes the components. This works fine.
Then we have the formik and that's the last thing that I have implemented after creating the the Comp2 that it's the "component" that we are creating with the addHandeler and deleteHandeler which creates the slider and a button to eliminate:
As you can see is very simple. And it works fine. But then when I click submit I get no values:
Thank you in advance.
import React from 'react';
import { useDispatch, useSelector } from "react-redux";
import history from "../../../history";
import { nanoid } from "nanoid";
/* MUI */
import { Container, Grid, Typography, Paper, TextField } from '#material-ui/core'
/* MUI edited Components */
import Appbar from '../../../components/Appbar';
import Button from '../../../components/Button';
import Translator from '../../../components/Translator';
import SliderSchedule from '../../../components/SliderSchedule';
/* Formik */
import { Formik, Form } from 'formik';
import * as Yup from "yup";
export default function Slots() {
const dispatch = useDispatch();
const paperStyle = { padding: 20, height: 'auto', width: 'auto', margin: "20px auto", backgroundColor: "#A9A9A9" }
function Comp2({ deleteHandeler, id, props }) {
return (
<Grid container item xs={12}>
<Grid item xs={11}> <SliderSchedule id={id} name={props.values.name} value={props.values.time} onChange={time => props.setFieldValue("time", time.target.value)} renderInput={(props) => <TextField {...props} />} /> </Grid>
<Grid item xs={1}> <Button type="button" style="Close" onClick={deleteHandeler}>CloseIcon</Button> </Grid>
</Grid>
);
}
const formSchema = {
time: []
};
function Comp1() {
const [sliderSchedule, setSliderSchedule] = React.useState([]);
const addHandeler = () => { setSliderSchedule(sliderSchedule => [...sliderSchedule, nanoid()]) };
const deleteHandeler = (removeId) => setSliderSchedule((sliderSchedule) => sliderSchedule.filter((id) => id !== removeId));
return (
<Formik
initialValues={formSchema}
onSubmit={values => {
console.log("Monday", values);
}}
render={props => (
<Form>
<Grid container justifyContent="center">
{sliderSchedule.map((id) => (<Comp2 key={id} id={id} deleteHandeler={() => deleteHandeler(id)} props={props} />))}
<Button variant="outlined" color="info" style="AddSlider" startIcon="AddIcon" onClick={addHandeler}> <Translator page="productSchedule" text="buttonAddSlider"></Translator> </Button>
<Button type="submit" variant="contained" color="primary"> Submit </Button>
</Grid>
</Form>
)}
/>
);
}
return (
<>
<Appbar></Appbar>
<Container>
<Grid container alignItems="flex-end">
{/* LA SUMA DE TOTS ELS xs={x} ha de ser xs={12} */}
<Grid container justifyContent="flex-start" item xs={12}>
<Typography variant="h3"> <Translator page="productSchedule" text="typographyTitle"></Translator> </Typography>
<Typography variant="h3"> 📅 </Typography>
</Grid>
<Grid item xs={12}>
<Paper elevation={10} style={paperStyle}>
<Grid container alignItems="flex-end">
<Grid container justifyContent="center" item xs="auto"> <Typography variant="h3"> <Translator page="productSchedule" text="typographyMonday"></Translator> </Typography> </Grid>
<Grid container justifyContent="center" item xs="auto"> <Comp1 /> </Grid>
</Grid>
</Paper>
</Grid>
</Grid>
</Container>
</>
);
}
i am getting the below error
TypeError: Cannot read properties of undefined (reading 'name') in react
data is not coming from the Products.
i am learning the react now and this is my first project so could you please help to sort out this issue.
index.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById("root")
);
App.js
import React from "react";
import Products from "./Components/Products/Products";
const App = () => {
return (
<div>
<Products />
</div>
);
};
export default App;
Products.jsx
import React from "react";
import { Grid } from "#material-ui/core";
import Product from "./Product/Product";
const products = [
{
id: 1,
name: "Macbook Air",
description: "Apple Macbook Air",
price: "$999",
},
{
id: 2,
name: "Macbook Pro",
description: "Apple Macbook Pro",
price: "$1199",
},
];
const Products = () => {
return (
<main>
<Grid container justify="center" spacing={4}>
{products.map((product) => (
<Grid item key={product.id} xs={12} sm={6} md={4} lg={3}>
<Product />
</Grid>
))}
</Grid>
</main>
);
};
export default Products;
Product.jsx
import React from "react";
import {
Card,
CardMedia,
CardContent,
CardActions,
Typography,
IconButton,
} from "#material-ui/core";
import { AddShoppingCart } from "#material-ui/icons";
import useStyles from "./styles";
const Product = ({ product }) => {
const classes = useStyles();
return (
<Card className={classes.root}>
<CardMedia className={classes.media} image="" title={product.name} />
<CardContent>
<div className={classes.cardContent}>
<Typography variant="h5" gutterBottom>
{product.name}
</Typography>
<Typography variant="h5">{product.price}</Typography>
</div>
<Typography variant="h2" color="textSecondary">
{product.description}
</Typography>
</CardContent>
<CardActions disableSpacing className={classes.cardActions}>
<IconButton aria-label="Add to cart">
<AddShoppingCart />
</IconButton>
</CardActions>
</Card>
);
};
export default Product;
How can i solve the above problem
For reference please find the attached image
You didn't pass the product prop to your <Product/> component, so it's undefined by default, and then you're referencing the property name in the Product component of an undefined prop, therefore you get the error.
Make the following change
const Products = () => {
return (
<main>
<Grid container justify="center" spacing={4}>
{products.map((product) => (
<Grid item key={product.id} xs={12} sm={6} md={4} lg={3}>
<Product product={product}/>
</Grid>
))}
</Grid>
</main>
);
};
It appears you are not passing the product as a prop to you <Product /> component.
Add this to your map:
{products.map((product) => (
<Grid item key={product.id} xs={12} sm={6} md={4} lg={3}>
<Product product={product}/>
</Grid>
))}
need to pass prop to your component
{products.map((product) => (
<Grid item key={product.id} xs={12} sm={6} md={4} lg={3}>
<Product product={product}/>
</Grid>
))}
I'm trying to set up my firebase authorization but keep running into the same problem. I'm not sure why, but for some reason, I get a white blank screen whenever I put AuthProvider around my components, my router, anything. As soon as I comment it out, my login and register pages pop back up again. Any help would be greatly appreciated.
I've gone through my code for hours and can't find the issue. I'm hoping it's something small that I'm missing, but really hope someone can help.
Also, I'm using Material-UI (though I doubt that makes a difference) and I have all of my API keys and such in a .env file (I have 3x checked that they're all correct).
Anyway, here's my authentication.js code:
import React, { useEffect, useState } from "react";
import app from "./firebase";
export const AuthContext = React.createContext();
export const AuthProvider = ({ children }) => {
const [currentUser, setCurrentUser] = useState(null);
const [pending, setPending] = useState(true);
useEffect(() => {
app.auth().onAuthStateChanged((user) => {
setCurrentUser(user)
setPending(false)
});
}, []);
if(pending){
return <>Please wait...</>
}
return (
<AuthContext.Provider
value={{
currentUser
}}
>
{children}
</AuthContext.Provider>
);
};
I also tried this way in my context folder:
import React, { useContext, useState, useEffect } from 'react';
import { auth } from '../firebase';
const AuthContext = React.createContext()
export function useAuth(){
return useContext(AuthContext)
}
export function AuthProvider({ children }) {
const [currentUser, setCurrentUser] = useState(null)
function register(email, password) {
return auth.createUserWithEmailAndPassword(email, password)
}
useEffect(() => {
const unsubscribe = auth.onAuthStateChanged(user => {
setCurrentUser(user)
})
return unsubscribe
}, [])
const value = {
currentUser,
register
}
return (
<AuthContext.Provider value={value}>
{children}
</AuthContext.Provider>
)
}
And here's my App.js code:
import React from 'react';
import 'fontsource-roboto';
import { BrowserRouter as Router, Route } from "react-router-dom";
import Home from './Home';
import Login from './Login';
import Register from './Register'
// import { AuthProvider } from '../authentication';
function App(){
return (
// <AuthProvider>
<Router>
<div>
<Route exact path="/" component={Home} />
<Route exact path="/login" component={Login} />
<Route exact path="/Register" component={Register} />
</div>
</Router>
// </AuthProvider>
)
}
export default App;
And my Register page if that helps:
import React, { useRef } from 'react';
import Avatar from '#material-ui/core/Avatar';
import Button from '#material-ui/core/Button';
import CssBaseline from '#material-ui/core/CssBaseline';
import TextField from '#material-ui/core/TextField';
import Link from '#material-ui/core/Link';
import Paper from '#material-ui/core/Paper';
import Grid from '#material-ui/core/Grid';
import Box from '#material-ui/core/Box';
import LockOutlinedIcon from '#material-ui/icons/LockOutlined';
import Typography from '#material-ui/core/Typography';
// import { Alert } from '#material-ui/lab';
import { makeStyles } from '#material-ui/core/styles';
// import { useAuth } from '../contexts/AuthContext';
// import register from '../contexts/AuthContext'
function Copyright() {
return (
<Typography variant="body2" color="textSecondary" align="center">
{'Copyright © '}
<Link color="inherit" href="https://kindredcompanion.app/">
Kindred Companion App
</Link>{' '}
{new Date().getFullYear()}
{'.'}
</Typography>
);
}
const useStyles = makeStyles((theme) => ({
root: {
height: '100vh',
},
image: {
// VTM Banner
backgroundImage: 'url(https://res.cloudinary.com/think-halcyon-llc/image/upload/v1617055998/Vampire:%20the%20Masquerade/vtm_banner_qze9dn.png)',
backgroundRepeat: 'no-repeat',
backgroundColor:
theme.palette.type === 'light' ? theme.palette.grey[50] : theme.palette.grey[900],
backgroundSize: 'cover',
backgroundPosition: 'center',
},
paper: {
margin: theme.spacing(8, 4),
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
},
avatar: {
margin: theme.spacing(1),
backgroundColor: theme.palette.secondary.main,
},
form: {
width: '100%', // Fix IE 11 issue.
marginTop: theme.spacing(1),
},
submit: {
margin: theme.spacing(3, 0, 2),
},
}));
export default function Register() {
const classes = useStyles();
const firstNameRef = useRef()
const lastNameRef = useRef()
const emailRef = useRef()
const passwordRef = useRef()
const passwordConfirmRef = useRef()
// const { register } = useAuth()
// const [error, setError] = useState("")
// const [loading, setLoading] = useState(false)
// async function handleSubmit(e) {
// e.preventDefault()
// if (passwordRef.current.value !== passwordConfirmRef.current.value) {
// return setError("Passwords do not match.")
// }
// try {
// setError("")
// setLoading(true)
// await register(emailRef.current.value, passwordRef.current.value)
// } catch {
// setError("Failed to create an account.")
// }
// setLoading(false)
// }
return (
<Grid container component="main" className={classes.root}>
<CssBaseline />
<Grid item xs={false} sm={4} md={7} className={classes.image} />
<Grid item xs={12} sm={8} md={5} component={Paper} elevation={6} square>
<div className={classes.paper}>
<Avatar className={classes.avatar}>
<LockOutlinedIcon />
</Avatar>
<Typography component="h1" variant="h5">
Register
</Typography>
<br />
{/* {error && <Alert severity="error">{error}</Alert>} */}
<form
className={classes.form}
// onSubmit={handleSubmit}
>
<Grid container spacing={2}>
<Grid item xs={12} sm={6}>
<TextField
autoComplete="fname"
name="firstName"
variant="outlined"
required
fullWidth
id="firstName"
label="First Name"
inputRef={firstNameRef}
autoFocus
/>
</Grid>
<Grid item xs={12} sm={6}>
<TextField
variant="outlined"
required
fullWidth
id="lastName"
label="Last Name"
name="lastName"
inputRef={lastNameRef}
autoComplete="lname"
/>
</Grid>
<Grid item xs={12}>
<TextField
variant="outlined"
required
fullWidth
id="email"
label="Email Address"
name="email"
inputRef={emailRef}
autoComplete="email"
/>
</Grid>
<Grid item xs={12}>
<TextField
variant="outlined"
required
fullWidth
name="password"
label="Password"
type="password"
id="password"
inputRef={passwordRef}
autoComplete="current-password"
/>
</Grid>
<Grid item xs={12}>
<TextField
variant="outlined"
required
fullWidth
name="password-confirm"
label="Password Confirmation"
type="password"
id="password"
inputRef={passwordConfirmRef}
autoComplete="current-password"
/>
</Grid>
</Grid>
<Button
type="submit"
fullWidth
variant="contained"
color="primary"
className={classes.submit}
// disabled={loading}
>
Sign Up
</Button>
<Grid container justify="flex-end">
<Grid item>
<Link href="/login" variant="body2">
Already have an account? Sign in
</Link>
</Grid>
</Grid>
<Box mt={5}>
<Copyright />
</Box>
</form>
</div>
</Grid>
</Grid>
);
}
Hoping someone can help me!
I actually had this issue too. My .env file was configured wrong and Firebase threw me an error where it said Invalid API key. Hopefully this helps!
Here is my code.
My goal is: when I click on Login button, content will show the Login card and when I click on Register button content will show the Register card.
As for my primary test, I used the following code:
import React,{useState} from 'react'
const Login=()=>{
return(
<form>
<label>Username:</label>
<input type="text" value="username"/>
<label>Password:</label>
<input type="password" value="password"/>
<button>Submit</button>
</form>
)
}
const Register=()=>{
return(
<form>
<label>Name:</label>
<input type="text" value="name"/>
<label>Username:</label>
<input type="text" value="username"/>
<label>Password:</label>
<input type="password" value="password"/>
<button>Register</button>
</form>
)
}
export default function App() {
const [click,setClick]=useState(false)
const handleClick=()=>{
setClick(true)
}
return (
<div>
<button onClick={handleClick}>Login</button>
{click?<Login/>:<Register/>}
</div>
)
}
And it works. In this way I tried to render functionalities in different components. It seems like not working. What am I missing here?
The following corrections will help you:-
You need to make App component responsible for maintaining click state and then pass only handler (setClick) to AppBar and only state (click) to Content.
import React, { useState } from "react";
import Login from "./Login";
import Register from "./Register";
import { 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";
import { Grid } from "#material-ui/core";
const useStyles = makeStyles(theme => ({
root: {
flexGrow: 1
},
menuButton: {
marginRight: theme.spacing(2)
},
title: {
flexGrow: 1
}
}));
function Appbar({ handleClick }) {
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}>
ReactApp
</Typography>
<Button color="inherit" onClick={()=>handleClick(true)}>
Login
</Button>
<Button color="inherit" onClick={()=>handleClick(false)}>
Register
</Button>
</Toolbar>
</AppBar>
</div>
);
}
function Content({ click }) {
const classes = useStyles();
return (
<div className={classes.root}>
<Grid container style={{ padding: 80 }} item>
<Grid xs={false} sm={4} />
<Grid xs={12} sm={8} />
{click ? (
<Login onClick={handleClick} />
) : (
<Register onClick={handleClick} />
)}
<Grid />
<Grid xs={false} sm={2} />
</Grid>
</div>
);
}
export default function App() {
const [click, setClick] = useState(true);
const handleClick = (value) => {
setClick(value);
};
return (
<div>
<Appbar handleClick={handleClick} />
<Content click={click} />
</div>
);
}
After clicking Button EditChannel component should render. Right now if I before clicking on button EditChannel re-rendering as many as times as list item. After clicking also happening the same. I only want after clicking on button. Please find below lines for code. After clicking EditChannel component should render
Channel card component
import React, { Fragment } from "react";
import { makeStyles } from "#material-ui/core/styles";
import { Typography, Button } from "#material-ui/core";
import Avatar from "#material-ui/core/Avatar";
import { Link } from "react-router-dom";
import { connect } from "react-redux";
import { channelFollow, channelFetchById } from "../../../redux/action/channel";
import EditChannel from "../../Channels/List/Edit";
const ChannelCard = props => {
const classes = useStyles();
const { channel, channelFetchById } = props;
const [open, setOpen] = React.useState(false);
const handleClickOpen = () => {
setOpen(true);
};
const view = (
<div className={classes.card}>
<Link to={`/channels/${channel._id}`} className={classes.link}>
<div className={classes.root}>
<Avatar
alt="Remy Sharp"
src={channel.avatar}
className={classes.bigAvatar}
/>
</div>
<div className={classes.title}>
<Typography
variant="subtitle1"
align="center"
className={classes.text}
>
{channel.channelName}
</Typography>
<Typography variant="body2" align="center">
{channel.introduction}
</Typography>
</div>
</Link>
<Typography variant="body2" align="center" className={classes.text1}>
{channel.follows ? channel.follows.length : 0} followers <br />
Language:{channel.language}
</Typography>
<div className={classes.center}>
<div className={classes.button}>
<div className={classes.buttons}>
<Button
variant="contained"
color="primary"
onClick={() => {
channelFetchById(channel._id);
handleClickOpen();
}}
>
Edit
</Button>
{handleClickOpen ? (
<EditChannel setOpen={setOpen} open={open} />
) : null}
</div>
<div>
<Button color="primary" variant="contained">
Delete
</Button>
</div>
</div>
<br />
</div>
</div>
);
return <Fragment>{view}</Fragment>;
};
export default connect(null, { channelFollow, channelFetchById })(ChannelCard);
I guess instead of handleClickOpen only open will work like this,
{open ? (
<EditChannel setOpen={setOpen} open={open} />
) : null}
Because handleClickOpen is click event not boolean variable