title: How to correctly work with data from React Context in useEffect/useCallback-hook
body: <p>I'm using a React Context to store data and to provide functionality to modify these data.</p>
  
  <p>Now, I'm trying to convert a Class Component into a Functional Component using React Hooks.</p>
  
  <p>While everything is working as expected in the Class, I don't get it to work in the Functional Component.</p>
  
  <p>Since my applications code is a bit more complex, I've created this small example (<a href="https://jsfiddle.net/Jens_Duttke/78y15o9p/" rel="nofollow noreferrer">JSFiddle link</a>), which allows to reproduce the problem:</p>
  
  <p>First the Context, which is the same for both, the Class and the Functional Component:</p>
  
  <pre class="lang-js prettyprint-override"><code>const MyContext = React.createContext();
  
  class MyContextProvider extends React.Component {
      constructor (props) {
          super(props);
  
          this.increase = this.increase.bind(this);
          this.reset = this.reset.bind(this);
  
          this.state = {
              current: 0,
              increase: this.increase,
              reset: this.reset
          }
      }
  
      render () {
          return (
              &lt;MyContext.Provider value={this.state}&gt;
                  {this.props.children}
              &lt;/MyContext.Provider&gt;
          );
      }
  
      increase (step) {
          this.setState((prevState) =&gt; ({
              current: prevState.current + step
          }));
      }
  
      reset () {
          this.setState({
              current: 0
          });
      }
  }
  </code></pre>
  
  <p>Now, here is the Class component, which works just fine:</p>
  
  <pre class="lang-js prettyprint-override"><code>class MyComponent extends React.Component {
      constructor (props) {
          super(props);
  
          this.increaseByOne = this.increaseByOne.bind(this);
      }
  
      componentDidMount () {
          setInterval(this.increaseByOne, 1000);
      }
  
      render () {
          const count = this.context;
  
          return (
              &lt;div&gt;{count.current}&lt;/div&gt;
          );
      }
  
      increaseByOne () {
          const count = this.context;
  
          if (count.current === 5) {
              count.reset();
          }
          else {
              count.increase(1);
          }
      }
  }
  MyComponent.contextType = MyContext;
  </code></pre>
  
  <p>The expected result is, that it counts to 5, in an interval of one second - and then starts again from 0.</p>
  
  <p>And here is the converted Functional Component:</p>
  
  <pre class="lang-js prettyprint-override"><code>const MyComponent = (props) =&gt; {
      const count = React.useContext(MyContext);
  
      const increaseByOne = React.useCallback(() =&gt; {
          console.log(count.current);
  
          if (count.current === 5) {
              count.reset();
          }
          else {
              count.increase(1);
          }
      }, []);
  
      React.useEffect(() =&gt; {
          setInterval(increaseByOne, 1000);
      }, [increaseByOne]);
  
      return (
          &lt;div&gt;{count.current}&lt;/div&gt;
      );
  }
  </code></pre>
  
  <p>Instead of resetting the counter at 5, it resumes counting.</p>
  
  <p>The problem is, that <code>count.current</code> in line <code>if (count.current === 5) {</code> is always <code>0</code>, since it does not use the latest value.</p>
  
  <p>The only way I get this to work, is to adjust the code on the following way:</p>
  
  <pre class="lang-js prettyprint-override"><code>const MyComponent = (props) =&gt; {
      const count = React.useContext(MyContext);
  
      const increaseByOne = React.useCallback(() =&gt; {
          console.log(count.current);
  
          if (count.current === 5) {
              count.reset();
          }
          else {
              count.increase(1);
          }
      }, [count]);
  
      React.useEffect(() =&gt; {
          console.log('useEffect');
  
          const interval = setInterval(increaseByOne, 1000);
  
          return () =&gt; {
              clearInterval(interval);
          };
      }, [increaseByOne]);
  
      return (
          &lt;div&gt;{count.current}&lt;/div&gt;
      );
  }
  </code></pre>
  
  <p>Now, the <code>increaseByOne</code> callback is recreated on every change of the context, which also means that the effect is called every second.<br>
  The result is, that it clears the interval and sets a new one, on every change to the context (You can see that in the browser console).<br>
  This may work in this small example, but it changed the original logic, and has a lot more overhead.</p>
  
  <p>My application does not rely on an interval, but it's listening for an event. Removing the event listener and adding it again later, would mean, that I may loose some events, if they are fired between the remove and the binding of the listener, which is done asynchronously by React.</p>
  
  <p>Has someone an idea, how it is expected to React, to solve this problem without to change the general logic?</p>
  
  <p>I've created a fiddle here, to play around with the code above:<br>
  <a href="https://jsfiddle.net/Jens_Duttke/78y15o9p/" rel="nofollow noreferrer">https://jsfiddle.net/Jens_Duttke/78y15o9p/</a></p>