skip to Main Content

I expect my console.log to show the current value of prevValueRef each one second. I checked and I saw that prevValueRef is increasing each second but it doesn’t show it in the console each second while I console it after setting the new value to my ref. It just shows it in first console.log:

const PreviousValueComponent = ({ value }) => {
  const prevValueRef = useRef();
  const changeRef = useRef(value); //value is a constant number like 4 for example.

  useEffect(() => {
    prevValueRef.current = changeRef.current;
    console.log(`prevValueRef is: ${prevValueRef.current}`)
  }, [changeRef.current]);

  useEffect(() => {
    const interval = setInterval(() => {
        changeRef.current++;
    }, 1000)
  }, [])

  return (
    <div>
      <p>Current Value: {value}</p>
      <p>Previous Value: {prevValueRef.current}</p>
    </div>
  );
};

I expected this in the console:

prevValueRef is:4
prevValueRef is:5
prevValueRef is:6
.
.
.

But it just shows the first one and when I force my component to a rerender after a while, it shows the updated value that is increased:

prevValueRef is:4
prevValueRef is:682

Edit: I expected my first useEffect to run after any change to it’s dependecy(here for ever) without any re-rendering. Was I doing the wrong way?

2

Answers


  1. The issue at hand is that useRef is just a plain javascript object. When you modify the ref.current React has no way of knowing that the value has changed and therefore does not re-render(https://react.dev/reference/react/useRef). If you want react to re-render on update of value you’d be better off using the useState-hook along the lines of this:

    const [previousValue, setPreviousValue] = useState();
    const [currentValue, setCurrentValue] = useState(value);
    

    You’d then alter these values by calling their respective setter, e.g.

    useEffect(() => {
        setPreviousValue(currentValue);
        console.log(`previousValue is: ${previousValue}`)
      }, [currentValue]);
    
      useEffect(() => {
        const interval = setInterval(() => {
            setCurrentValue(currentValue++);
        }, 1000)
      }, [])
    

    EDIT::
    Adding solution as discussed in comments. Where one of the useEffect-calls are replaced by a function which the setInterval-function calls:

      const updatePrevValueRef = (value) => {
        prevValueRef.current = value;
        console.log(`prevValueRef is: ${prevValueRef.current}`)
      }
    
      useEffect(() => {
        const interval = setInterval(() => {
            changeRef.current++;
            updatePrevValueRef(changeRef.current);
        }, 1000)
      }, [])
    
    Login or Signup to reply.
  2.  I have done some changes in your code, you can try this :
        
     
    
     const [currentValue, setCurrentValue] = useState(value);
                  const [previousValue, setPreviousValue] = useState(null);
                
                  useEffect(() => {
                    const interval = setInterval(() => {
                      setPreviousValue(currentValue);
                      setCurrentValue((prevValue) => prevValue + 1);
                    }, 1000);
                
                    return () => clearInterval(interval);
                  }, [currentValue]);
                
                  useEffect(() => {
                    console.log(`Previous Value: ${previousValue}`);
                  }, [previousValue]);
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search