简体   繁体   中英

Elements not displaying with .map() in react functional component with useEffect hook

I am creating an array of categories in useEffect callback, it works fine when i console.log it.

But then when I.map() it, the resulting array is empty.

import React, { useEffect } from 'react';

export const Categories = (props) => {
    let categories = [];

    useEffect(() => {
        props.films.forEach((film) => {
            if (categories.findIndex(item => item === film.category) === -1)
            {
                categories.push(film.category);
                console.log(categories);
            }

        })
    }, [props.films, categories])

    return (
        <div>
            {categories.map((category) => {
                return (
                    <div>
                        {category}
                    </div>
                )
            })}
        </div>
    );
}

Does someone have an idea?

You should use a state value for categories:

const [categories, setCategories] = React.useState([])

useEffect(() => {
    let categories = []
    props.films.forEach((film) => {
        if (categories.findIndex(item => item === film.category) === -1)
        {
            categories.push(film.category);
            console.log(categories);
        }

    })
    setCategories(categories)
}, [props.films])

The component is not getting re-rendered when the data in categories is getting changed. In order to render the categories you need to store the data using useState .

import React, { useEffect, useState } from 'react';

export const Categories = (props) => {
    const [categories, setCategories] = useState([]);

    useEffect(() => {
        let filmCategories = []
        props.films.forEach((film) => {
            if (categories.findIndex(item => item === film.category) === -1)
            {
                filmCategories.push(film.category);
                console.log(filmCategories);
            }
        })
        setCategories(filmCategories)
    }, [props.films])

    return (
        <div>
            {categories.map((category) => {
                return (
                    <div>
                        {category}
                    </div>
                )
            })}
        </div>
    );
}

Hope this helps.

I think you maybe be new to react. I recommend you to take a look at React State and Lifecycle

You are using the react hook useEfect which will be called after your component is rendered in DOM

I can think of two possible solutions to solve this

1) using the react hook useState

import React, { useEffect } from 'react';

export const Categories = (props) => {
    //Make the local variable into a variable representing state
    let [categories, setCategories] = useState([]);

    useEffect(() => {
        const result = [...categories];
        props.films.forEach((film) => {
            if (result.findIndex(item => item === film.category) === -1)
            {
                result.push(film.category);
                console.log(result);
            }

        })
        //Set the state value to trigger a re-render of your component
        if(result.length !== categories.length)
            setCategories(result);
    }, [props.films, categories])

    return (
        <div>
            {categories.map((category) => {
                return (
                    <div>
                        {category}
                    </div>
                )
            })}
        </div>
    );
}

2) If re-rendering is not required, remove the useEffect hook

import React, { useEffect } from 'react';

export const Categories = (props) => {
    let categories = props.films.map(film => {
            if (categories.findIndex(item => item === film.category) === -1)
            {
                categories.push(film.category);
                console.log(categories);
            }
     }


    return (
        <div>
            {categories.map((category) => {
                return (
                    <div>
                        {category}
                    </div>
                )
            })}
        </div>
    );
}

If the useEffect react hook is required, then solution 1 is better

If there is no need to re-render the react component, then solution 2 is better

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM