title: React Hook useCallback not getting updated state when invoked
body: <p>I am developing this application where I double click the page and create a new item. Then I notify a websockets server to broadcast this creation to all other users listening to it. On the other user end I must add this new item, so everybody gets synchronized.</p>
  <p>I am using react hooks and this is my first app from the scratch using it. I am having several problems like this in this application, but I selected this flow to illustrate the basic problem. It must cover most issues.</p>
  <p>When I call the <code>useCallback</code> to add the item on the &quot;other user&quot; side, the <code>items</code> state is old (empty). So no matter how many times I create items, I will only have one on the page, the one I just created.</p>
  <p>This is a sample of the code:</p>
  <pre><code>import React, { useEffect, useState, useCallback } from 'react';
  import io from 'socket.io-client';
  
  let socket;
  
  function App() {
    const [items, setItems] = useState({});
  
    const createItem = useCallback((data) =&gt; {
      const id = generateId();
      const newItem = { id, ...data };
      const newItems = { ...items, [id]: newItem };
  
      setItems(newItems)
  
      // When I create a new item, I notify the server to broadcast it
      socket.emit('itemCreated', newItem)
    }, [items, setItems])
  
    const doCreateItem = useCallback((item) =&gt; {
      // When someone else creates an item, it should be invoked be invoked
      const newItems = { ...items, [item.id]: item };
      setItems(newItems)
    }, [items]);
  
    useEffect(() =&gt; {
      // Connects to the server
      socket = io('ws://localhost:8090', {
        transports: ['websocket'],
        path: '/ws'
      });
  
      // Listens to event
      socket.on('createitem', (data) =&gt; {
        doCreateItem(data)
      });
  
      // I cannot add doCreateItem here, otherwise it will call this effect everytime doCreateItem is executed
    }, []);
  
    return (
      &lt;div
        onDoubleClick={
          (e) =&gt; {
            createItem({});
          }
        }
      &gt;
  
        {
          Object.values(items).map(item =&gt; {
            return (
              &lt;div&gt;{item.id}&lt;/div&gt;
            )
          })
        }
  
      &lt;/div&gt;
    );
  }
  
  export default App;
  </code></pre>
  <p>The <code>doCreateItem</code> has the items dependency. One the other hand, the <code>useEffect</code> dependency list doesn't contain <code>doCreateItem</code> mostly because it will reinvoke the <code>useEffect</code> callback everytime I receive a new item from the server. And also because I want this effect to be executed only once (on component mounting). I tried splitting the <code>useEffect</code> in two, one for the connection and another for the listeners, but the same happens.</p>
  <p>I actually had several problems like this one. A callback is executed more than I was expecting or the state is not updated on the callback.</p>
  <p>Could someone clarify how we should get around this problem?</p>
  <p>Thanks in advance!</p>
  <p><strong>Edit</strong></p>
  <p>As suggested by <strong>@Ross</strong>, I changed the <code>setItems</code> calls to receive a callback and return the new state. That helped with the <code>setItems</code> dependency. But I still can't read <code>items</code> in the <code>doCreateItem</code> function. It is always empty.</p>
  <p>Something funny that I noticed, is that if I stop using the <code>useCallback</code> and recreate the functions on each render, it doesn't have the updated state on that function, but it does have outside the function:</p>
  <pre><code>function App() {
    const [items, setItems] = useState({});
   
    console.log('Rendered again and knows the state &gt;', items)
    const doCreatePostIt = (data) =&gt; {
      console.log('Empty &gt;', items)
      // ...
    };
    // ...
  }
  </code></pre>