title: Event-driven approach in React?
body: <p>I'd like to &quot;fire an event&quot; in one component, and let other components &quot;subscribe&quot; to that event and do some work in React.</p>
  <p>For example, here is a typical React project.</p>
  <p>I have a model, fetch data from server and several components are rendered with that data.</p>
  <pre class="lang-js prettyprint-override"><code>interface Model {
     id: number;
     value: number;
  }
  
  const [data, setData] = useState&lt;Model[]&gt;([]);
  useEffect(() =&gt; {
     fetchDataFromServer().then((resp) =&gt; setData(resp.data));
  }, []);
  
  &lt;Root&gt;
     &lt;TopTab&gt;
       &lt;Text&gt;Model with large value count:  {data.filter(m =&gt; m.value &gt; 5).length}&lt;/Text&gt;
     &lt;/TobTab&gt;
     &lt;Content&gt;
        &lt;View&gt;
           {data.map(itemData: model, index: number) =&gt; (
              &lt;Item key={itemData.id} itemData={itemData} /&gt;
           )}
        &lt;/View&gt;
     &lt;/Content&gt;
     &lt;BottomTab data={data} /&gt;
  &lt;/Root&gt;
  </code></pre>
  <p>In one child component, a model can be edited and saved.</p>
  <pre class="lang-js prettyprint-override"><code>const [editItem, setEditItem] = useState&lt;Model|null&gt;(null);
  &lt;Root&gt;
     &lt;TopTab&gt;
       &lt;Text&gt;Model with large value count:  {data.filter(m =&gt; m.value &gt; 5).length}&lt;/Text&gt;
     &lt;/TobTab&gt;
     &lt;ListScreen&gt;
        {data.map(itemData: model, index: number) =&gt; (
            &lt;Item 
               key={itemData.id} 
               itemData={itemData} 
               onClick={() =&gt; setEditItem(itemData)}
            /&gt;
        )}
     &lt;/ListScreen&gt;
     {!!editItem &amp;&amp; (
         &lt;EditScreen itemData={editItem} /&gt;
     )}
     &lt;BottomTab data={data} /&gt;
  &lt;/Root&gt;
  </code></pre>
  <p>Let's assume it's EditScreen:</p>
  <pre class="lang-js prettyprint-override"><code>const [model, setModel] = useState(props.itemData);
  
  &lt;Input 
     value={model.value}
     onChange={(value) =&gt; setModel({...model, Number(value)})}
  /&gt;
  &lt;Button 
     onClick={() =&gt; {
         callSaveApi(model).then((resp) =&gt; {
             setModel(resp.data);
             // let other components know that this model is updated
         })
     }}
  /&gt;
  </code></pre>
  <p>App must let <code>TopTab</code>, <code>BottomTab</code> and <code>ListScreen</code> component to update data</p>
  <ul>
  <li><strong>without</strong> calling API from server again (because EditScreen.updateData already fetched updated data from server) and</li>
  <li>not passing <code>updateData</code> function as props (because in most real cases, components structure is too complex to pass all functions as props)</li>
  </ul>
  <p>In order to solve above problem effectively, I'd like to fire an event (e.g. &quot;model-update&quot;) with an argument (changed model) and let other components subscribe to that event and change their data, e.g.:</p>
  <pre class="lang-js prettyprint-override"><code>// in EditScreen
  updateData().then(resp =&gt; {
     const newModel = resp.data;
     setModel(newModel);
     Event.emit(&quot;model-updated&quot;, newModel);
  });
  
  // in any other components
  useEffect(() =&gt; {
     // subscribe model change event
     Event.on(&quot;model-updated&quot;, (newModel) =&gt; {
        doSomething(newModel);
     });
     // unsubscribe events on destroy
     return () =&gt; {
       Event.off(&quot;model-updated&quot;);
     }
  }, []);
  
  // in another component
  useEffect(() =&gt; {
     // subscribe model change event
     Event.on(&quot;model-updated&quot;, (newModel) =&gt; {
        doSomethingDifferent(newModel);
     });
     // unsubscribe events on destroy
     return () =&gt; {
       Event.off(&quot;model-updated&quot;);
     }
  }, []);
  
  </code></pre>
  <p>Is it possible using React hooks?</p>
  <p><strong>How to implement event-driven approach in React hooks?</strong></p>