title: Created element loses state
body: <p>I am trying to make a function that returns a component that can be customized depending on the type it should handle. I have created a small replication which is the following:</p>
  <pre><code>import { Button } from '@chakra-ui/react';
  import React from 'react';
  
  function createTestElementWithStateAndChangeAlert&lt;T&gt;(props: {
    onChange: (newValue: T) =&gt; any;
    retrieve: { on: (callback: (newValue: T) =&gt; any) =&gt; any };
  }) {
    return function TestElement() {
      const [state, setState] = React.useState&lt;{ retrievedValue?: T; value?: T; open?: boolean }&gt;({});
  
      React.useEffect(() =&gt; {
        props.retrieve.on((newValue) =&gt;
          setState((prevState) =&gt; ({ ...prevState, retrievedValue: newValue }))
        );
  
        // I should put an unsuscriber here but it's not important just right now
      }, [props.retrieve]);
  
      function handleClick() {
        if (state.retrievedValue) {
          setState((prevState) =&gt; ({ ...prevState, value: state.retrievedValue, open: true }));
          props.onChange(state.retrievedValue);
        } else {
          console.log('Not updated beceause no retrieved value');
        }
      }
  
      return (
        &lt;Button onClick={handleClick}&gt;
          Click {state.value} {state.open &amp;&amp; 'Open'}
        &lt;/Button&gt;
      );
    };
  }
  
  type TestType = number;
  
  let currentCallback: (value: TestType) =&gt; any;
  
  setInterval(() =&gt; {
    currentCallback &amp;&amp; currentCallback(Math.random() * 1000);
  }, 1500);
  
  function TestElementProvider(props: { onChange: (value: number) =&gt; any }) {
    function createProvider() {
      return createTestElementWithStateAndChangeAlert&lt;TestType&gt;({
        onChange: props.onChange,
        retrieve: {
          on: (callback) =&gt; (currentCallback = callback),
        },
      });
    }
    const [TestElement, setTestElement] = React.useState(() =&gt; createProvider());
  
    React.useEffect(() =&gt; {
      setTestElement(() =&gt; createProvider());
    }, [props.onChange]);
  
    return &lt;TestElement /&gt;;
  }
  
  const Home = () =&gt; {
    const [state, setState] = React.useState&lt;{ value: number }&gt;({ value: 0 });
  
    function handleUpdate(value: number) {
      console.log('onChange', value);
      setState({ value });
    }
  
    return (
      &lt;&gt;
        {state.value}
        &lt;TestElementProvider onChange={handleUpdate} /&gt;
      &lt;/&gt;
    );
  };
  
  export default Home;
  </code></pre>
  <p>In this case, I create the component each time the props.onChange changes through the React.useEffect hook in order to keep updated the onChange method, the problem is that the state of the TestElement is lost on each re-creation.</p>
  <p>I have tried to work around this situation without the useState and useEffect as follows:</p>
  <pre><code>import { Button } from '@chakra-ui/react';
  import React from 'react';
  
  function createTestElementWithStateAndChangeAlert&lt;T&gt;(props: {
    onChange: (newValue: T) =&gt; any;
    retrieve: { on: (callback: (newValue: T) =&gt; any) =&gt; any };
  }) {
    return function TestElement() {
      const [state, setState] = React.useState&lt;{ retrievedValue?: T; value?: T; open?: boolean }&gt;({});
  
      React.useEffect(() =&gt; {
        props.retrieve.on((newValue) =&gt;
          setState((prevState) =&gt; ({ ...prevState, retrievedValue: newValue }))
        );
  
        // I should put an unsuscriber here but it's not important just right now
      }, [props.retrieve]);
  
      function handleClick() {
        if (state.retrievedValue) {
          setState((prevState) =&gt; ({ ...prevState, value: state.retrievedValue, open: true }));
          props.onChange(state.retrievedValue);
        } else {
          console.log('Not updated beceause no retrieved value');
        }
      }
  
      return (
        &lt;Button onClick={handleClick}&gt;
          Click {state.value} {state.open &amp;&amp; 'Open'}
        &lt;/Button&gt;
      );
    };
  }
  
  type TestType = number;
  
  let currentCallback: (value: TestType) =&gt; any;
  
  setInterval(() =&gt; {
    currentCallback &amp;&amp; currentCallback(Math.random() * 1000);
  }, 1500);
  
  function TestElementProvider(props: { onChange: (value: number) =&gt; any }) {
    function createProvider() {
      return createTestElementWithStateAndChangeAlert&lt;TestType&gt;({
        onChange: props.onChange,
        retrieve: {
          on: (callback) =&gt; (currentCallback = callback),
        },
      });
    }
    const [TestElement] = React.useState(() =&gt; createProvider());
  
    return &lt;TestElement /&gt;;
  }
  
  const Home = () =&gt; {
    const [state, setState] = React.useState&lt;{ value: number }&gt;({ value: 0 });
  
    function handleUpdate(value: number) {
      console.log('oldValue', state.value);
      setState({ value });
    }
  
    return (
      &lt;&gt;
        {state.value}
        &lt;TestElementProvider onChange={handleUpdate} /&gt;
      &lt;/&gt;
    );
  };
  
  export default Home;
  </code></pre>
  <p>In this case, the expected behavior was to get a console.log message with 'oldValue' updated to the last old one, but instead, it keeps giving me the same old value as the first time, because the<br />
  &quot;onClick&quot; event on the button points to the first function passed, instead of the last one.</p>
  <p>This should not be a problem if I were working with properties that don't depend on the previous ones, but in my case, I wanted to work with an array that should be filled with each interaction. To do so, I set the new value to the oldArray + the newValue. But this is not working because the oldArray is always empty, so the obtained value is always a 1 element array.</p>
  <p>Can anyone please help me understand a better way to implement this idea?</p>