Why do I continue to have stale data in my useEffect?

Asked
Active3 hr before
Viewed126 times

7 Answers

useeffect
90%

Thanks for contributing an answer to Stack Overflow!, Stack Overflow Public questions & answers , Meta Stack Overflow

ReactDOM.render(<Test/>, document.getElementById("root"))

function Test(){
    const [array, setArray] = React.useState([2,3,4,5]);
    const renderCounter = React.useRef(0);
    
    function mutateInPlace(e){
        renderCounter.current++;
        // some random in-place mutations
        array[1] = 4;
        array[2] = 11;
        array.sort((a,b)=>a-b);
        setArray(array);
    }
    
    function mutateOutOfPlace(e) {
        renderCounter.current++;
        // creating a new array
        let arrayCopy = array.slice(0);
        setArray(arrayCopy);
    }
    
    console.log("re-rendered");
    return (
        <div>
            {renderCounter.current}
            <br/>
            <button onClick={mutateInPlace}>mutate in-place</button>
            <button onClick={mutateOutOfPlace}>mutate out-of-place</button>
        </div>
    );
}
load more v
88%

useState is analogous to class components’ state and setState. We use this hook to have atomic containers of state inside a function component.,To fetch API data in function components, we use useState and useEffect hooks.,Thus, we have stale-while-refresh caching working in a function component.

Pretag
 Pretag team - issue, fix, solve, resolve
72%

The stale closure captures variables that have outdated values.,The stale closure problem occurs when a closure captures outdated variables.,log() is a stale closure. The closure log() has captured message variable having "Current value is 0".

function createIncrement(incBy) {
   let value = 0;

   function increment() {
      value += incBy;
      console.log(value);
   }

   const message = `Current value is ${value}`;

   function log() {
      console.log(message);
   }
   return [increment, log];
}

const [increment, log] = createIncrement(1);
increment(); // logs 1
increment(); // logs 2
increment(); // logs 3
// Does not work!
log(); // logs "Current value is 0"
load more v
65%

We have a truly portable solution for our problem. But guess what… there’s still a little more to do. Specifically, we need to make the solution compatible with props.,Let’s start by getting rid of the manual change to the ref in the “Click me”button.,Let’s focus on how we can avoid these stale references with our states and props.

e.g.

const [count, setCount] = useState(0);
const ref = useRef(count);

useEffect(() => {
   ref.current = count
}, [count])
load more v
75%

React’s effects are a completely different animal than the lifecycle methods of class-based components. The abstraction level differs, too.,I hope these example have convinced you that working with effects is different from lifecycle methods and that it is ultimately not beneficial to try to mimic these methods.,If I have misunderstood you, would you have a concrete example?

Pretag
 Pretag team - issue, fix, solve, resolve
40%

Why am I seeing stale props or state inside my function?,You can continue to use the exact same APIs as you always have; they’ll continue to work.,The useCallback Hook lets you keep the same callback reference between re-renders so that shouldComponentUpdate continues to work:

function Example() {
  const [count, setCount] = useState(0);
  useEffect(() => {
    document.title = `You clicked ${count} times`;
  });
  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}
load more v
22%

There are two ways to import hooks: from preact/hooks or preact/compat.,Hooks can be used in any component, and avoid many pitfalls of the this keyword relied on by the class components API. Instead of accessing properties from the component instance, hooks rely on closures. This makes them value-bound and eliminates a number of stale data problems that can occur when dealing with asynchronous state updates.,To get a reference to a DOM node inside a functional components there is the useRef hook. It works similar to createRef.

class Counter extends Component {
  state = {
    value: 0
  };

  increment = () => {
    this.setState(prev => ({ value: prev.value +1 }));
  };

  render(props, state) {
    return (
      <div>
        Counter: {state.value}
        <button onClick={this.increment}>Increment</button>
      </div>
    );
  }
}
load more v

Other "useeffect-undefined" queries related to "Why do I continue to have stale data in my useEffect?"