Jackal
Jackal

Reputation: 3521

React assign values to an array

I'm trying to handle some star rating according to some data from an api. The problem is that I have created an array for the stars and nothing is rendered. If I console .log inside the fetchMovieDetails I can see there is data. What am I missing? I even tried var stars = useState([]) but still same result

export default function MovieDetails({ match }) {
    const [movie, setMovie] = useState({});
    var stars = [];

    useEffect(() => {
        fetchMovieDetails();
    }, []);

    async function fetchMovieDetails() {

       // get data from api

        // Handle star rating
        var rating = (response.rating/ 2).toFixed(1);

        for (var i = 0; i < 5; i++) {
            var star = {};
            if (i < ~~rating) star = 'filled';
            else if (rating % 1 === 0) star = 'half-filled';
            stars.push(star);
        }

        setMovie(response.data);
    }

    return (
        <div className="movie-container">
            <div className="movie-grid">
                <div className="movie-rating">
                    <div className="star-rating">

                        // nothing is rendered here
                        {stars.map((star) => (
                            <span className="{`icon-star ${star}`}">
                                <span className="path1"></span>
                                <span className="path2"></span>
                            </span>
                        ))}
                        {(movie.rating/ 2).toFixed(1)} / 5
                    </div>
                </div>
            </div>
        </div>
    );
}

Upvotes: 0

Views: 146

Answers (2)

Kalhan.Toress
Kalhan.Toress

Reputation: 21901

If you prefer to not to keep stars in the state, and if you need to move the star logic in to a separate section then useMemo will help with it.

async function fetchMovieDetails() {
     // get data from api
    .....
    setMovie(response.data);
}

const stars = useMemo(() => {
    if (!movie.rating) {
        //if movie is not fetched then return an empty array
        return [];
    }

    const rating = (movie.rating/ 2).toFixed(1);
    const starsTemp = [];
    for (let i = 0; i < 5; i++) {
        var star = {};
        if (i < ~~rating) star = 'filled';
        else if (rating % 1 === 0) star = 'half-filled';
        starsTemp.push(star);
    }

    return starsTemp;
}, [movie]); //when movie gets changed call this function

Why i prefer this is, lets say you can add a rating by clicking on a star, and then lets say you need to show the updated rating, with your approach you have to change two states, rating property of movie and the stars, so basically if a one state is depending on a another state, its better to do like this.

Upvotes: 1

Viet Dinh
Viet Dinh

Reputation: 1951

I guest var stars is always re-declare. Why don't you using the useState like:

const [stars, setStarts] = useState([]);

useEffect(() => {
    fetchMovieDetails();
}, []);

async function fetchMovieDetails() {

    // get data from api

    // Handle star rating
    var rating = (response.rating/ 2).toFixed(1);
    var stars = [];
    
    for (var i = 0; i < 5; i++) {
        var star = {};
        if (i < ~~rating) star = 'filled';
        else if (rating % 1 === 0) star = 'half-filled';
        stars.push(star);
    }
    
    setStarts(stars);
    setMovie(response.data);
}

Upvotes: 2

Related Questions