Skip to content
Advertisement

Why React Component unmounts on each useEffect dependency change?

I am trying to learn React by building a web application. Since I want to learn it step by step, for now I don’t use Redux, I use only the React state and I have an issue.

This is my components architecture:

           App.js
             |
    _________|_________
   |                   |
Main.js              Side.js
   |                   |
Game.js              Moves.js

As you can see, I have the main file called App.js, in the left side we have the Main.js which is the central part of the application which contains Game.js where actually my game is happening. On the right side we have Side.js which is the sidebar where I want to display the moves each player does in the game. They will be displayed in Moves.js.

To be more clear think at the chess game. In the left part you actually play the game and in the right part your moves will be listed.

Now I will show you my code and explain what the problem is.

// App.js

const App = React.memo(props => {     
    let [moveList, setMovesList] = useState([]);

    return (
        <React.Fragment>  
            <div className="col-8">                                            
                <Main setMovesList={setMovesList} />                        
            </div>
            <div className="col-4">  
                <Side moveList={moveList} />
            </div>    
        </React.Fragment>
    );
});

// Main.js

const Main = React.memo(props => { 
    return (
        <React.Fragment>                
            <Game setMovesList={props.setMovesList} />
        </React.Fragment>
    );
});

// Game.js

const Game= React.memo(props => { 
    useEffect(() => {
        function executeMove(e) {
            props.setMovesList(e.target);
        }

        document.getElementById('board').addEventListener('click', executeMove, false);    

        return () => {            
            document.getElementById('board').removeEventListener('click', executeMove, false);              
        };
    }) 
    
    return (
        // render the game board
    );
});

// Side.js

const Side= React.memo(props => { 
    return (
        <React.Fragment>                
            <Moves moveList={props.moveList} />
        </React.Fragment>
    );
});

// Moves.js

const Moves= React.memo(props => { 
    let [listItems, setListItems] = useState([]);

    useEffect(() => {
        let items = [];                    

        for (let i = 0; i < props.moveList.length; i++) {
            items.push(<div key={i+1}><div>{i+1}</div><div>{props.moveList[i]}</div></div>)                                          
        }

        setListItems(items);

        return () => { 
            console.log('why this is being triggered on each move?') 
        }; 

    }, [props.moveList]);

    return (
        <React.Fragment>                
            {listItems}  
        </React.Fragment>
    );
});

As you can see on my code, I have defined the state in App.js. On the left side I pass the function which updates the state based on the moves the player does. On the right side I pass the state in order to update the view.

My problem is that on each click event inside Game.js the component Moves.js unmounts and that console.log is being triggered and I wasn’t expected it to behave like that. I was expecting that it will unmount only when I change a view to another.

Any idea why this is happening ? Feel free to ask me anything if what I wrote does not make sense.

Advertisement

Answer

Thanks for explaining your question so well – it was really easy to understand.

Now, the thing is, your component isn’t actually unmounting. You’ve passed props.movesList as a dependency for the usEffect. Now the first time your useEffect is triggered, it will set up the return statement. The next time the useEffect gets triggered due to a change in props.movesList, the return statement will get executed.

If you intend to execute something on unmount of a component – shift it to another useEffect with an empty dependency array.

User contributions licensed under: CC BY-SA
3 People found this is helpful
Advertisement