Search code examples
javascriptreactjsreact-hooksjestjs

Using setState inside of the useEffect is causing a Maximum Update dept exceeded error in testing


I have a function that takes a props value in a component and flattens it into a form the component can use. This needs to happen every time the props value changes. I put the setState in a useEffect with the props value as one of the dependencies.

This works fine in the browser but I get the error from the question title when running the Jest tests.

Here's basically what my code looks like:


const mapThing = (notFlatStructure) => {
    let flattendStructure = [];
    notFlatStructure.forEach((mainItem) => {
        flattendStructure.append({
            id: mainItem.id,
            text: mainItem.text,
            isToggle: true
        });

        if (mainItem.subItems && mainItem.subItems.length > 0) {
            mainItem.subItems.forEach((subItem) => {
                flattendStructure.append({
                    id: subItem.id,
                    text: subItem.text,
                    isToggle: true
                });
            });
        }
    });

    return flattendStructure;
 };

const myComponent = (props) => {

    const [mappedThing, setMappedThing] = useState(mapThing(props.thing));
 
    useEffect(() => {
       setMappedThing(mapThing(props.thing));
    }, [props.thing]);
 
    const handleBlur = (e) => {
        props.thingChanged(e);
    };

    const handleClick = (row) => {
        let found = mappedThing.find((el) => el.id = row.id);
        found.isToggle = !found.isToggle;
        setMappedThing(mappedThing);
    };

    return (
        <div>
            {
                mappedThing.map((row) => {
                    <div>
                        <input onBlur={handleBlur} value={row.text}></input>
                        <button onClick={(e) => handleClick(row)}></button>
                    </div>                  
                })
            }
        </div>
    );
 };

Is there a standard way to have mappedThing above set every time the props change without using a useEffect? Any time I take the useEffect away the component quits updating.


Solution

  • Drew Reese in the comments was correct. The code was an anti-pattern in React. After restructuring the component and splitting some functionality off into small, sub components, I was able to create the component without flattening the underlying data structure and removing the need for the setState in the useEffect. Thanks, Mr. Reese for pointing our my error. I learned a lot having to work through making this align with React's expectations.