setState hook does not set value - javascript

I'm triggering setClickedMovieId using onClick event. I also use useEffect to check if the value of state is set correctly, however, it consoles out the default value (zero).
I need to save the id of a clicked item in order to be able to use it at <NavLink to={"movie/" + clickedMovieId}>.
const MovieCards = () => {
const { movies } = useContext(MoviesContext);
const [clickedMovieId, setClickedMovieId] = useState<number>(0);
useEffect(() => {
console.log('Current value of movie id state', clickedMovieId);
}, [clickedMovieId]);
return (
<div >
<Grid container spacing={1}>
{movies.map((movie) => (
<Grid item xs={6} sm={2} key={movie.id}>
<NavLink to={"movie/" + clickedMovieId}>
<Card className="card">
<CardActionArea>
<CardMedia
component="img"
/>
</CardActionArea>
<CardActions>
<Button size="small" color="primary">
<FavoriteBorderIcon />
</Button>
<Button size="small" color="primary" onClick={() => setClickedMovieId(movie.id)}>
{movie.rating}
</Button>
</CardActions>
</Card>
</NavLink>
</Grid>
))}
</Grid>
</div>
);
}
export default MovieCards;
How can I fix it?
Thanks!

Solution:
<NavLink to={"movie/" + movie.id}>

Related

Unable to pass down useState props for adding count

I have three components im trying to connect together to add the number of items I have in a shopping cart. I have the main component which creates the CartCount object and setCartCount functionality:
function MinerStore() {
const [cartCount, setCartCount] = useState([0]);
const addToCart = () => {
setCartCount(cartCount + 1);
};
return (
<>
<div >
<StoreNav cartCount={cartCount} />
<div>
<StoreCard addToCart={addToCart} />
</div>
</div>
</>
);
}
I also then have the two components I am trying to show the added count on as well as the added count functionality:
export default function StoreCard(addToCart) {
return (
<ThemeProvider theme={theme}>
<main>
<Container>
<Grid container spacing={3}>
{data.map((data) => (
<Grid item key={data.id} xs={12} sm={6} md={3}>
<Card>
<CardContent>
</CardContent>
<CardActions>
<div>
<Button onClick={addToCart}>
Add to Cart
</Button>
</div>
</CardActions>
</Card>
</Grid>
))}
</Grid>
</Container>
</main>
</ThemeProvider>
);
}
export default function StoreNav(cartCount) {
return (
<AppBar position="static">
<Toolbar>
<IconButton>
<Badge badgeContent={cartCount} color="primary">
<ShoppingCartIcon />
</Badge>
</IconButton>
</Toolbar>
</AppBar>
);
}
You've set your initial state as an array [0].
Set it as as 0 and check it out
And ofc as the people above mentioned you should either use props or {addToCart} in the child's parameter.
Then on button should look as such:
<Button onClick={addToCart /* or props.addToCart */}>Add to Cart </Button>

I have a component. But the onClick function isn't running

I have a component which i have imported into another component. When I click the component, the onclick function refuses to run.
This is the code for the component
const HomeFeedCard = ({ name, image, published, quantity, weight }) => {
const classes = useHomeFeedCardStyles()
return (
<Grid item xs={6} md={3} sm={4} lg={3}>
<Paper elevation={5}>
<img src={image?.url} alt='Product' className={classes.image} />
<div className={classes.container}>
<Avatar
alt='image'
src='https//user.png'
sx={{ width: 56, height: 56, mr: 1 }}
/>
<div className={classes.textContainer}>
<Typography variant='h6' component='body'>
<LinesEllipsis text={` ${name}`} />
</Typography>
<Typography>{`${quantity} left | ${weight}KG`}</Typography>
</div>
</div>
</Paper>
</Grid>
)
}
THIS IS THE function that runs the onClick function. The console returns nothing
<HomeFeedCard
key={product._id}
name={product.productName}
published={product.published}
image={product.images[0]}
quantity={product.quantity}
weight={product.weight}
onClick={() => console.log('product', product.productName)}
/>
Your onClick is not defined in your function HomeFeedCard.
const HomeFeedCard = ({ name, image, published, quantity, weight, onClick }) => {
return (
<div onClick={onClick} />
)
}
If you don't know which properties you want to set use: https://reactjs.org/docs/jsx-in-depth.html#spread-attributes
In the HomeFeedCard, you are not expecting an onClick function as a prop.
You need to explicitly bind the onClick to an actual element. You can wrap content inside HomeFeedCardwith adiv`.
OR, pass onClick further to Grid if accepts a click handler.
const HomeFeedCard = ({
name,
image,
published,
quantity,
weight,
onClick
}) => {
const classes = useHomeFeedCardStyles();
return (
<div onClick={onClick}>
<Grid item xs={6} md={3} sm={4} lg={3}>
<Paper elevation={5}>
<img src={image?.url} alt="Product" className={classes.image} />
<div className={classes.container}>
<Avatar
alt="image"
src="https//user.png"
sx={{ width: 56, height: 56, mr: 1 }}
/>
<div className={classes.textContainer}>
<Typography variant="h6" component="body">
<LinesEllipsis text={` ${name}`} />
</Typography>
<Typography>{`${quantity} left | ${weight}KG`}</Typography>
</div>
</div>
</Paper>
</Grid>
</div>
);
};
<HomeFeedCard
key={product._id}
name={product.productName}
published={product.published}
image={product.images[0]}
quantity={product.quantity}
weight={product.weight}
onClick={() => console.log("product", product.productName)}
/>

ReactJS- Calling a dynamic link based on a prop value

i have a cards.js which has the following function. Now the calling method passes three values . header1, header2 and Link (this is the *.js page that has to be called)
export default function Cards(props) {
const classes = useStyles();
return (
<div className="App">
<Card className={classes.card} variant="outlined">
<CardContent>
<Typography
variant={"h5"}
gutterBottom
>
{props.header1}
</Typography>
<Typography
variant={"caption"} >
{props.header2}
</Typography>
<Divider className={classes.divider} light />
<Button variant="contained" color="secondary" onClick={()=> (call either link1.js or link2.js )}>
Lets goooooo!
</Button>
</CardContent>
</Card>
</div>
);
}```
calling method
class UIM extends Component {
render() {
return (
<div className="text-page">
<Grid container alignItems="center" justify="space-evenly" >
<Grid ><Cards header1="card 1 for a task1" header2="click text2" link="link1"/></Grid>
<Grid ><Cards header1=" card 2 for task 2" header2=" click text 2" link="link2"/></Grid>
</Grid>
</div>
)
}
}
I am new to react and learning right now, so wondering if such a thing is possible or should i use router to route to different pages (ie. call either link1.js or link2.js ) ??
I found out by by adding pathname:props.link i can get the button to link to multiple locations within the material ui button.
<Card className={classes.card} variant="outlined">
<CardContent>
<Typography
variant={"h5"}
gutterBottom
>
{props.header1}
</Typography>
<Typography
variant={"caption"} >
{props.header2}
</Typography>
<Divider className={classes.divider} light />
<Button variant="contained" color="secondary">
<NavLink to={{pathname:props.link}}>Lets goooooo!</NavLink>
</Button>
</CardContent>
</Card>

Error when passing a functional component to a class component as a component prop

I create a functional component and a class component.
In the render method I want to call my functional component as a component prop.
My code:
function projectList(props) {
const { classes } = props
return (
<div>
{projects.slice(0, 5).map(project => (
<Card className={classes.card} key={project.id}>
<CardHeader
classes={{ title: classes.h6, subheader:
classes.subtitle1 }}
title={project.projectName}
subheader={project.h5}
/>
<CardActionArea>
<CardMedia
component="img"
alt={project.h5}
className={classes.media}
image={project.img}
/>
<CardContent>
<Typography paragraph>
{project.paragraph}
</Typography>
</CardContent>
</CardActionArea>
<CardActions className={props.classes.actions}>
<Button
className={props.classes.projectButton}
component={Link}
to={project.pathname}
size="medium"
color="secondary"
>
Project Details
</Button>
</CardActions>
</Card>
))}
</div>
)
}
projectList.propTypes = {
classes: PropTypes.any.isRequired, // eslint-disable-line
}
class Projects extends Component {
static propTypes = {
classes: PropTypes.any.isRequired, // eslint-disable-line
}
render() {
const { classes } = this.props
return (
<Grid container className={classes.projectPage}
direction="row">
<Grid item xs />
<Grid item>
<Grid container alignItems="center" direction="column">
{/* Title */}
<Grid item>
<Typography className={classes.h5} variant="h5">Latest
Projects</Typography>
</Grid>
<Grid item xs={12} sm={6} component={projectList} />
<Grid item className={classes.nextButton}>
<Button
className={classes.contained}
size="medium"
variant="contained"
onClick={this.handleShowMore}
>
See More
</Button>
</Grid>
</Grid>
</Grid>
<Grid item xs />
</Grid>
)
}
}
export default withStyles(styles)(Projects)
I have this error message appearing
index.js:1452 Warning: Failed prop type: The prop classes is marked as required in projectList, but its value is undefined.
Anyone could help me fix this ?
Not sure where that <Grid/> component comes from but you could pass an inline wrapper for projectLists and return it as a jsx element (you would need a capital first letter though):
<Grid item xs={12} sm={6} component={() => <ProjectList classes={classes} />} />
Don't forget to change the decleration to capital letter:
function ProjectList(props) {
...

React: If statements inside a map function

I'm struggling with this for a while now, I'm building a page so the user can create forms dynamically I have one react component that creates the forms and one that renders it, I'm currently facing problems with editing the forms already created.
const GigApplicationRenderer = (props) => {
const {
questions,
onSelectDelete,
onSelectEdit,
classes,
theme,
handleClickOpen,
handleClose,
open
} = props;
return (
<Fragment>
{questions.map((element, index) => (
<div className={classes.li} key={element.title}>
<Grid container spacing={24}>
<Grid item xs={12}>
{element.type === 'input' ? (
<Paper index={index} className={classes.paper}>
<Title
onSelectEdit={onSelectEdit}
onSelectDelete={onSelectDelete}
element={element}
handleClose={handleClose}
open={open}
/>
<TextField
className={classes.textField}
value=""
label="answer text"
margin="normal"
/>
</Paper>
) : element.type === 'radiobox' ? (
<Paper className={classes.paper}>
<Title
onSelectEdit={onSelectEdit}
onSelectDelete={onSelectDelete}
element={element}
handleClose={handleClose}
open={open}
/>
{element.options.map(option => (
<ListItem key={option} className={classes.itemsList}>
<RadioGroup>
<FormControlLabel
label={option}
value={option}
control={<Radio color="primary" />}
/>
</RadioGroup>
</ListItem>
))}
</Paper>
) : element.type === 'checkbox' ? (
<Paper className={classes.paper}>
<Title
onSelectEdit={onSelectEdit}
onSelectDelete={onSelectDelete}
element={element}
handleClose={handleClose}
open={open}
/>
{element.options.map(option => (
<ListItem key={option} className={classes.itemsList}>
<FormControlLabel
label={option}
value={option}
control={<Checkbox checked={false} color="primary" />}
/>
</ListItem>
))}
<Divider light />
</Paper>
) : null}
</Grid>
</Grid>
</div>
))}
</Fragment>
);
};
this is the component that renders the code, it has some if statements that check the properties of the forms created and renders it accordingly.
this is the title component:
const Title = (props) => {
const {
element, onSelectDelete, onSelectEdit, index, handleClose, open
} = props;
return (
<Grid container spacing={24}>
{console.log(element.title)}
<Grid item xs={12} sm={9}>
<Typography style={{ textAlign: 'left' }} variant="subheading" gutterBottom>
{element.title}
</Typography>
</Grid>
<Grid item xs={12} sm={3}>
<Tooltip enterDelay={100} leaveDelay={100} placement="bottom" title="Edit">
<IconButton onClick={onSelectEdit(element, index)} aria-label="Edit">
<EditIcon />
</IconButton>
</Tooltip>
<Tooltip enterDelay={100} leaveDelay={100} placement="bottom" title="Delete">
<IconButton aria-label="Delete">
<DeleteIcon onClick={onSelectDelete(element)} />
</IconButton>
</Tooltip>
</Grid>
<Dialog open={open} onClose={handleClose} aria-labelledby="form-dialog-title">
<DialogTitle id="form-dialog-title">
blabla
</DialogTitle>
<DialogContent>
<DialogContentText>
To subscribe to this website, please enter your email address here. We will send updates
occasionally.
</DialogContentText>
<TextField
autoFocus
// value={element.title}
margin="dense"
label="question title"
fullWidth
/>
</DialogContent>
<DialogActions>
<Button onClick={handleClose} color="primary">
Cancel
</Button>
<Button onClick={handleClose} color="primary">
Save
</Button>
</DialogActions>
</Dialog>
</Grid>
);
};
I want it to open a dialog with the values of the element clicked so the user could edit it, the problem is that no matter which button was clicked, on the dialog, it always renders the last element of the form.
On the function onSelectEdit though, I get the correct element, I think it is happening because of the if statements of the first component.
the questions array look like this:
questions: [
{
title: 'Why do you want this job?',
type: 'input'
},
{
title: 'Do you know Javascript?',
type: 'radiobox',
options: ['yes', 'no']
},
{
title: 'What techs your know?',
type: 'checkbox',
options: ['html', 'css']
}
],
is there a way to render the correct element when the dialog opens?
I'm also open to any suggestion on how to accomplish this.

Categories

Resources