Search code examples
reactjsreact-hooksuse-state

How to push new value in array useState in react


I want when I click on a card of the movie name, this movie name is pushed in useSate. The problem is when I click on the same card, data is saved in the useState as an array. But when I click on a different card previous value of the useState is deleted.

Here is my code. movie is a single object.

const MovieCard = ({ movie }) => {
    const [firstCat, setFirstCat] = React.useState([]);
    



    const movieList = (movie) => {
        setFirstCat([...firstCat, movie]);
    }

    console.log(firstCat);

    return (
        <div className='mt-3 cursor-pointer' onClick={() => movieList(movie)}>
            <div className="max-w-sm bg-white rounded-lg border border-gray-200 shadow-md">

                <img className="rounded-t-lg" src="/docs/images/blog/image-1.jpg" alt="" />

                <div className="p-5">

                    <h5 className="mb-2 text-xl font-bold tracking-tight text-gray-900">{movie.Title}</h5>

                </div>
            </div>
        </div>
    );
};

export default MovieCard;

when clicking on the same card, useState is like this, clicking on the same card

When clicking on the different card enter image description here


Solution

  • Your problem is you scoped your states only in MovieCard which means each MovieCard will have different states.

    You need to add states on the upper/parent component of MovieCard. Let's assume you have MovieList contains all MovieCard

    const MovieList = () => {
       const [firstCat, setFirstCat] = React.useState([]);
    
       console.log(firstCat);
    
       return <div>
          <MovieCard movie={movie} setFirstCat={setFirstCat}/>
       <div/>
    }
    

    And modify your MovieCard like below

    const MovieCard = ({ movie, setFirstCat }) => {
    
        const movieList = (movie) => {
            setFirstCat([...firstCat, movie]);
        }
    
        return (
            <div className='mt-3 cursor-pointer' onClick={() => movieList(movie)}>
                <div className="max-w-sm bg-white rounded-lg border border-gray-200 shadow-md">
    
                    <img className="rounded-t-lg" src="/docs/images/blog/image-1.jpg" alt="" />
    
                    <div className="p-5">
    
                        <h5 className="mb-2 text-xl font-bold tracking-tight text-gray-900">{movie.Title}</h5>
    
                    </div>
                </div>
            </div>
        );
    };
    
    export default MovieCard;
    

    This technique is called state lifting