I try to change the icon and add it to favorites when I click on it. It works fine, my icon is changed but it impacts all my images icons instead of one. How can I fix this? Here is my code:
import React, { useState, useEffect } from "react";
import AddCircleOutlineIcon from '@mui/icons-material/AddCircleOutline';
import CheckCircleOutlineIcon from '@mui/icons-material/CheckCircleOutline';
import ExpandCircleDownIcon from '@mui/icons-material/ExpandCircleDown';
import PlayCircleIcon from '@mui/icons-material/PlayCircle';
const Row = () => {
const [image, setImage] = useState([])
const [favorite, setFavorite] = useState(false);
useEffect(() => {
...
}, []);
const addToFavorite = () => {
...
}
return (
<div >
{image.map((item) => {
return (
<div key={item.id}>
<span>{item.title}</span>
<span>{item.description}</span>
<img src={...} alt={image.title}/>
<div onClick={() => setFavorite(!favorite)}>
{favorite ? < CheckCircleOutlineIcon onClick={() => addToFavorite()} /> : < AddCircleOutlineIcon onClick={() => addToFavorite()} />}
</div>
)
})}
</div>
);
}
export default Row;
CodePudding user response:
Your problem is favorite
state is only true/false value, when it's true, all images will have the same favorite
value.
The potential fix can be that you should check favorite
based on item.id
instead of true/false value
Note that I added updateFavorite
function for handling favorite state changes on your onClick
Here is the implementation for multiple favorite items
import React, { useState, useEffect } from "react";
import AddCircleOutlineIcon from '@mui/icons-material/AddCircleOutline';
import CheckCircleOutlineIcon from '@mui/icons-material/CheckCircleOutline';
import ExpandCircleDownIcon from '@mui/icons-material/ExpandCircleDown';
import PlayCircleIcon from '@mui/icons-material/PlayCircle';
const Row = () => {
const [image, setImage] = useState([])
const [favorite, setFavorite] = useState([]);
useEffect(() => {
...
}, []);
const updateFavorite = (itemId) => {
let updatedFavorite = [...favorite]
if(!updatedFavorite.includes(itemId)) {
updatedFavorite = [...favorite, itemId]
} else {
updatedFavorite = updatedFavorite.filter(favoriteItem => itemId !== favoriteItem)
}
setFavorite(updatedFavorite)
}
const addToFavorite = () => {
...
}
return (
<div >
{image.map((item) => {
return (
<div key={item.id}>
<span>{item.title}</span>
<span>{item.description}</span>
<img src={...} alt={image.title}/>
<div onClick={() => updateFavorite(item.id)}>
{favorite.includes(item.id) ? < CheckCircleOutlineIcon onClick={() => addToFavorite()} /> : < AddCircleOutlineIcon onClick={() => addToFavorite()} />}
</div>
)
})}
</div>
);
}
export default Row;
Here is the implementation for a single favorite item
import React, { useState, useEffect } from "react";
import AddCircleOutlineIcon from '@mui/icons-material/AddCircleOutline';
import CheckCircleOutlineIcon from '@mui/icons-material/CheckCircleOutline';
import ExpandCircleDownIcon from '@mui/icons-material/ExpandCircleDown';
import PlayCircleIcon from '@mui/icons-material/PlayCircle';
const Row = () => {
const [image, setImage] = useState([])
const [favorite, setFavorite] = useState(); //the default value is no favorite item initially
useEffect(() => {
...
}, []);
const updateFavorite = (itemId) => {
let updatedFavorite = favorite
if(itemId !== updatedFavorite) {
updatedFavorite = itemId
} else {
updatedFavorite = null
}
setFavorite(updatedFavorite)
}
const addToFavorite = () => {
...
}
return (
<div >
{image.map((item) => {
return (
<div key={item.id}>
<span>{item.title}</span>
<span>{item.description}</span>
<img src={...} alt={image.title}/>
<div onClick={() => updateFavorite(item.id)}>
{favorite === item.id ? < CheckCircleOutlineIcon onClick={() => addToFavorite()} /> : < AddCircleOutlineIcon onClick={() => addToFavorite()} />}
</div>
)
})}
</div>
);
}
export default Row;
CodePudding user response:
This is what you're looking for based on the code you've provided:
import { useState, useEffect } from "react";
const Item = ({ item }) => {
const [favorite, setFavorite] = useState(false);
const toggleFavorite = () => setFavorite((favorite) => !favorite);
return (
<div>
<span>{item.title}</span>
<span>{item.description}</span>
<span onClick={toggleFavorite>
{favorite ? "[♥]" : "[♡]"}
</span>
</div>
);
};
const Row = () => {
const [items, setItems] = useState([]);
useEffect(() => {
// use setItems on mount
}, []);
return (
<div>
{items.map((item) => <Item item={item} key={item.id} />)}
</div>
);
};
export default Row;
You can break up your code into smaller components that have their own states and that's what I did with the logic that concerns a single item. I've created a new component that has its own state (favorited or not).