Home > Software engineering >  React Component UseEffect isn't rerendering upon prop change
React Component UseEffect isn't rerendering upon prop change

Time:02-16

I have a dynamic Countdown Timer In React:
Basic React Counter

This Timer is a component (MovementTimer.js) & the main component (GameRoom.js) is calling Timer's render method, passing thru props.

This is the render Timer function that's being called below upon every GameRoom render

    renderTimer = () => {
        console.log('*** Timer RERENDER ***');
        console.log(this.state.turn_time);
        console.log(this.state.last_time);

        if(this.state.turn_time != null && this.state.last_time != null){
            const props = {
                time : this.state.turn_time,
                last_time : this.state.last_time

            }

            return(
                <MovementTimer {...props}/>
            )
        } else {
            return(
                <p>Undefined Timer.</p>
            )
        }
    }

This is the render method of GameRoom.js

   render() {

        if(this.state.guest){
            console.log('loaded in ! '   this.state.guest);
            //              Put into return statement for DEBUG     {this.state.turn ? "TRUE" : "FALSE"} 
            return (
                <div className="main">
                    {this.renderBoard()}
                    {this.renderTimer()}

                    {}
                    <p className="welcome"> 

                    {this.state.userResponseData}

                    {
                    this.state.guest[0] ? (this.state.turn ? "It's your opponent's turn." : "It's your turn, move!") : (this.state.turn ? "It's your turn, move!" : "It's your opponent's turn.")
                    
                    }</p>
    
                </div>
            )
        }

        return (
            <div className="main">
                {this.renderBoard()}
                
                <p className="welcome"> {this.state.turn ? "TRUE" : "FALSE"} Loading {this.state.userResponseData}</p>

            </div>
        )
    }
}

Basically the issue is, whenever GameRoom.js rerender's, the renderTimer() function passes in updated props to the MovementTimer, however the timer doesn't reset. I was trying to use a useRef state boolean but it was buggy and wasn't working.

MovementTimer.js component

import React, {useRef, clearState,useState,useCallback} from 'react'


const MovementTimer = (props) => {
    console.log('Re initizalized')
    const time = parseInt(props.time);
    const last_time = parseInt(props.last_time);

    //clearState()
    console.log( 

        "Estimated Time:\n" 
        ((last_time time*1000) - Date.now() )/1000
        
    );

    let [counter, setCounter] = React.useState(Math.round( ((last_time time*1000) - Date.now() )/1000 ) );
    // const reinit = () => {
    //     setCounter(time)
    // }

    console.log(counter);
    console.log(last_time);

    React.useEffect(() => {

        counter > 0 && setTimeout(() => setCounter(
            counter - 1
        ), 1000); //Set this too Due time - last time / 1000 (for secs)

        
        if(counter === 0){
            const socketProtocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'
    
            const socket = new WebSocket(socketProtocol (window.location.href).split(':')[1] ':5000');
    
            socket.onopen = async () => {
                await socket.send(JSON.stringify({
                    query_type : 't0',
                    room_id: (window.location.pathname).slice(6)
                }));
                socket.close();
                
    
            }
            setCounter(Math.round( ((last_time time*1000) - Date.now() )/1000 ))
        }    



      }, [counter]);
    


    return (
        <div>
            {counter}
        </div>
    )
}

export default MovementTimer

In this component, I useEffect for the timer countdown, and pass in the time difference in seconds (using props that have been passed down) Is there anyway to check if props change, and reset the useEffect?

In that if statement (counter === 0), I manually set it back using setCounter. however i dont know how to check for prop change. whenever last_time prop is updated.

CodePudding user response:

The second parameter in your useEffect is what the function listens to for changes. If you just want to rerun the function in useEffect when a specific variable changes, add it to the array. For example, if you want to rerun it when variable x changes, you would write it like this:

React.useEffect(() => { /* do stuff */ }, [counter, x]);

Documentation: Conditionally firing an effect

  • Related