ReactJS - Lifting state up vs keeping a local state : <p>At my company we're migrating the front-end of a web application to ReactJS.
We are working with create-react-app (updated to v16), without Redux.
Now I'm stuck on a page which structure can be simplified by the following image:</p>

<p><a href="https://i.stack.imgur.com/B1gM0.png" rel="noreferrer"><img src="https://i.stack.imgur.com/B1gM0.png" alt="Page structure"></a></p>

<p>The data displayed by the three components (SearchableList, SelectableList and Map) is retrieved with the same backend request in the <code>componentDidMount()</code> method of MainContainer. The result of this request is then stored in the state of MainContainer and has a structure more or less like this:</p>

<pre><code>state.allData = {
  left: {
    data: [ ... ]
  },
  right: {
    data: [ ... ],
    pins: [ ... ]
  }
}
</code></pre>

<p>LeftContainer receives as prop <code>state.allData.left</code> from MainContainer and passes <code>props.left.data</code> to SearchableList, once again as prop.</p>

<p>RightContainer receives as prop <code>state.allData.right</code> from MainContainer and passes <code>props.right.data</code> to SelectableList and <code>props.right.pins</code> to Map.</p>

<p>SelectableList displays a checkbox to allow actions on its items. Whenever an action occur on an item of SelectableList component it may have side effects on Map pins.</p>

<p>I've decided to store in the state of RightContainer a list that keeps all the ids of items displayed by SelectableList; this list is passed as props to both SelectableList and Map. Then I pass to SelectableList a callback, that whenever a selection is made updates the list of ids inside RightContainer; new props arrive in both SelectableList and Map, and so <code>render()</code> is called in both components.</p>

<p>It works fine and helps to keep everything that may happen to SelectableList and Map inside RightContainer, but I'm asking if this is correct for the <strong>lifting-state-up</strong> and <strong>single-source-of-truth</strong> concepts.</p>

<p>As feasible alternative I thought of adding a <code>_selected</code> property to each item in <code>state.right.data</code> in MainContainer and pass the select callback three levels down to SelectableList, handling all the possible actions in MainContainer. But as soon as a selection event occurs this will eventually force the loading of LeftContainer and RightContainer, introducing the need of implementing logics like <code>shouldComponentUpdate()</code> to avoid useless <code>render()</code> especially in LeftContainer.</p>

<p><strong>Which is / could be the best solution to optimise this page from an architectural and performance point of view?</strong></p>

<p>Below you have an extract of my components to help you understand the situation.</p>

<p><strong>MainContainer.js</strong></p>

<pre><code>class MainContainer extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      allData: {}
    };
  }

  componentDidMount() {
    fetch( ... )
      .then((res) =&gt; {
        this.setState({
          allData: res
        });
      });
  }

  render() {
    return (
      &lt;div className="main-container"&gt;
        &lt;LeftContainer left={state.allData.left} /&gt;
        &lt;RightContainer right={state.allData.right} /&gt;
      &lt;/div&gt;
    );
  }
}

export default MainContainer;
</code></pre>

<p><strong>RightContainer.js</strong></p>

<pre><code>class RightContainer extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      selectedItems: [ ... ]
    };
  }

  onDataSelection(e) {
    const itemId = e.target.id;
    // ... handle itemId and selectedItems ...
  }

  render() {
    return (
      &lt;div className="main-container"&gt;
        &lt;SelectableList
          data={props.right.data}
          onDataSelection={e =&gt; this.onDataSelection(e)}
          selectedItems={this.state.selectedItems}
        /&gt;
        &lt;Map
          pins={props.right.pins}
          selectedItems={this.state.selectedItems}
        /&gt;
      &lt;/div&gt;
    );
  }
}

export default RightContainer;
</code></pre>

<p>Thanks in advance!</p>
