title: FlatList is slow when the list is large (100s of items) - state change performance issue
body: <p><code>FlatList</code> is slow when the data set is large (100s of items). Each click on an item's <code>checkbox</code> takes around <strong>2 seconds</strong>. Actually, the first click on a checkbox takes around a second; then, it increases by 20% till it reaches 2.5 seconds. It stays at 2.5 seconds for any clicks after that. It seems that the bottleneck is <code>changing state</code>. Is there any way to improve the performance? Please, see a simplified code, which demonstrates the issue below.</p>
  <pre class="lang-js prettyprint-override"><code>const TestScreen = () =&gt; {
      // Build a testing data set. 
      // In the actual application, the data set is stored in Redux. 
      let contactList = []; 
      for (let i = 0; i &lt; 700; i++) { contactList.push({ mobileNo: i.toString() }); } 
  
      const [contactPhoneNumberList2, setContactPhoneNumberList2] = React.useState([]);
  
      const _onPress = async (item) =&gt; {
          // The following step takes no time because the number of selected items is very small! 
          const indexOfSelectedItem = contactPhoneNumberList2.findIndex(element =&gt; element === item.mobileNo);        
  
          // Get the current time BEFORE calling the state-changing step
          const now = new Date(); 
  
          // The user clicked on an already selected item -&gt; let's unselect it (remove it from the list of selected items)
          if (indexOfSelectedItem &gt; -1) {
              let abc = [ ...contactPhoneNumberList2 ]; 
              abc.splice(indexOfSelectedItem, 1);
  
              // Updating state takes around 2 seconds 
              // await is used below to help identify the bottleneck. It is NOT part of the production code. 
              await setContactPhoneNumberList2(abc); // &lt;&lt;&lt; PROBLEM &lt;&lt;&lt; 
              
              // Get the current time AFTER calling the state-changing step
              const now2 = new Date(); 
              console.log(&quot;state-changin took (milliseconds):&quot;, now2 - now, &quot;onPress - IF - after state change&quot;, ); 
          }
          // The user clicked on an unselected item -&gt; let's select it (add it to the list of selected items)
          else {
              // Updating state takes around 2 seconds 
              // await is used below to help identify the bottleneck. It is NOT part of the production code. 
              await setContactPhoneNumberList2(contactPhoneNumberList2.concat([item.mobileNo])); // &lt;&lt;&lt; PROBLEM &lt;&lt;&lt; 
              
              // Get the current time AFTER calling the state-changing step
              const now2 = new Date(); 
              console.log(&quot;state-changin took (milliseconds):&quot;, now2 - now, &quot;onPress - IF - after state change&quot;, ); 
          }
      }; 
  
      const _renderItem = ({ item, index, }) =&gt; {
          // The following step takes no time because the number of selected items is very small! 
          const itemWasSelected = contactPhoneNumberList2.find(element =&gt; element === item.mobileNo);     
  
          return (
              &lt;ListItem&gt;
                  &lt;ListItem.CheckBox checked={itemWasSelected} onPress={() =&gt; _onPress(item)}/&gt;
                  &lt;ListItem.Content&gt;
                      &lt;ListItem.Title&gt;{item.mobileNo}&lt;/ListItem.Title&gt;
                   &lt;/ListItem.Content&gt;
              &lt;/ListItem&gt;
          );
      };
  
      return (
          &lt;FlatList
              data={contactList} 
  
              // just in case, the natural key (item.mobileNo) is repeated, the index is appended to it
              keyExtractor={(item, index) =&gt; item.mobileNo + index.toString()} 
          
              renderItem={_renderItem}
  
              // I tried the following, but none of them seems to helpful, in this case 
              // removeClippedSubviews={false}
              // initialNumToRender={5}
              // maxToRenderPerBatch={10} // good 
              // windowSize={10}
  
              // getItemLayout={_getItemLayout}
          /&gt;
      );  
  }; 
  
  export default TestScreen;
  </code></pre>