title: Filtering Components on React Native
body: <p>I'm trying to make a filtering checkbox list options to filter out the news to show on a feed. My app isn't yet getting information from database so I'm basically creating by hand to test the methods.</p>
  
  <p>The variables I have are topics (which is a state prop), and feedNews, topics is an array with the topics that the user wishes to see in the feed, while feedNews are all the news components that exist to show in the feed.</p>
  
  <p>e.g. of topics</p>
  
  <pre><code>this.state = {
    topics: ['News-1','News-2','News-3']
  }
  </code></pre>
  
  <p>e.g. of components for feedNews</p>
  
  <pre><code>const feedNews = [
      {name:'News-1', comp: &lt;FeedNews key={101} name="News-1" /&gt;},
      {name:'News-2', comp: &lt;FeedNews key={102} name="News-2" /&gt;},
      {name:'News-3', comp: &lt;FeedNews key={103} name="News-3" /&gt;},
      {name:'News-1', comp: &lt;FeedNews key={104} name="News-1" /&gt;},
      {name:'News-3', comp: &lt;FeedNews key={105} name="News-3" /&gt;}
  ]
  </code></pre>
  
  <p>Note: the keys on each component was just for a test</p>
  
  <p>Basically what I have on my render of the class is calling a function that returns the filtered array of components:</p>
  
  <pre><code>filterFeedNews(){
      let topics = this.state.topics;
      return feedNews.filter((item) =&gt; {
          return topics.indexOf(item.name)!==-1;
      }).map(item =&gt; item.comp);
  }
  </code></pre>
  
  <p>Now this function works everytime I open the app for the first time, but if I actually change the topics array with my filter options (list of checkboxes), sometimes there are options that disappear and they weren't the options that I had chosen. Btw, the update filter function is this:</p>
  
  <pre><code>updateFilter(newsName, value){
      let newNewsTopics = this.state.topics;
      if(value){
          newNewsTopics.push(newsName);
      }else{
          newNewsTopics.splice(newNewsTopics.indexOf(newsName),1);
      }
      this.props.dispatch(setNewsFilter(newNewsTopics));
      this.setState({
          newsTopics: newNewsTopics,
      });
  }
  </code></pre>
  
  <p>this function is called by bind within each checkbox as action (because of the name of the props)</p>
  
  <pre><code>onClick(){
      this.action(this.name, !this.state.value);
      this.setState({
          value: !this.state.value,
      });
  }
  </code></pre>
  
  <p>My question is, what am I doing wrong on those functions, or is it "normal" for this to happen in react-native</p>
  
  <p>PS: if there's only one news per topic, there is no problem. This only doesn't work when there are more than one news per topic</p>
  
  <p><strong>UPDATE</strong></p>
  
  <p>I'm not sure if this is the problem, but if the problem is being ScrollView instead of ListView for filtering and rendering purposes</p>
  
  <pre><code>render(){
          return (
              &lt;View style={styles.root}&gt;
                  &lt;Toolbar home={true} options={true} title='Feed' actionOptions={this.optionsAction.bind(this)}/&gt;
                  &lt;View style={styles.flexContainer}&gt;
                      &lt;ScrollView style={styles.flexContainer}&gt;
                          {this.filterFeedNews()}
                      &lt;/ScrollView&gt;
                  &lt;/View&gt;
                  &lt;View style={styles.spacing} /&gt;
                  {this.options()}
              &lt;/View&gt;
          );
      }
  </code></pre>
  
  <h1><strong>Solution</strong></h1>
  
  <p>So basically the main wasn't even the filtering, the problem was more in terms of the rendering of the components. With the help of a colleague I had to change a bit the structure of what I posted above.
  What changed:</p>
  
  <pre><code>const feedNews = [
      {name:'News-1', ...otherProps},
      {name:'News-2', ...otherProps},
      {name:'News-3', ...otherProps},
      {name:'News-1', ...otherProps},
      {name:'News-3', ...otherProps}
  ];
  </code></pre>
  
  <p>added a dataSource to my state</p>
  
  <pre><code>dataSource: ds.cloneWithRows(feedNews),
  </code></pre>
  
  <p>my filter feed function was changed as well to adapt to the new way of thought</p>
  
  <pre><code>filterFeedNews(){
          let topics = this.state.newsTopics;
          let feed = feedNews.filter((item) =&gt; {
              return topics.includes(item.name);
          });
          const ds = new ListView.DataSource({rowHasChanged: (r1, r2) =&gt; r1 !== r2});
          this.setState({dataSource: ds.cloneWithRows(feed)});
      }
  </code></pre>
  
  <p>my update filter action had to be changed as well</p>
  
  <pre><code>updateFilter(newsName, value){
          let newNewsTopics = this.state.topics;
          if(value){
              newNewsTopics.push(newsName);
          }else{
              newNewsTopics.splice(newNewsTopics.indexOf(newsName), 1);
          }
          this.props.dispatch(setNewsFilter(newNewsTopics));
          this.setState({
              newsTopics: newNewsTopics,
          }, () =&gt; this.filterFeedNews());
      }
  </code></pre>
  
  <p>and my render instead of the ScrollView it now has a ListView</p>
  
  <pre><code>&lt;ListView
          style={styles.flexContainer}
          dataSource={this.state.dataSource}
          removeClippedSubviews={false}
          renderRow={(rowData, sectionID, rowID) =&gt; this.renderRow(rowData, sectionID, rowID)}
          enableEmptySections={true}
  /&gt;
  </code></pre>
  
  <p><strong>Pro:</strong> it doesn't have the problems I had with my previous approach</p>
  
  <p><strong>Con:</strong> LayoutAnimation that I used everytime the component is updated doesn't work with the ListView, so the user only has feedback of the filtration if the news in the feed have their pictures</p>
  
  <h1><strong>Solution maintaining ScrollView</strong></h1>
  
  <p>In case if I want to keep my initial approach with Scroll View, my solution was basically this</p>
  
  <pre><code>updateFilter(newsName, value){
       let newNewsTopics = this.state.topics;
       if(value){
           newNewsTopics.push(newsName);
       }else{
           newNewsTopics.splice(newNewsTopics.indexOf(newsName), 1);
       }
       this.props.dispatch(setNewsFilter(newNewsTopics));
       this.setState({
          newsTopics: newNewsTopics,
      });
  }
  
  filterFeedNews(){
      let topics = this.state.topics;
      let i = 0;
      return feedNews.filter((item) =&gt; {
          return topics.includes(item.name);
      }).map((item) =&gt; {
          return (&lt;FeedNews key={++i} name={item.name}/&gt;);
      });
  }
  </code></pre>
  
  <p>Where this.state.topics maintains the structure (an array of strings), whereas feedNews basically turns into an array of objects like in the example above for the previous <strong>solution</strong>, and then it's converted with the function filterFeedNews using filter and map o "convert" into an array of components.
  In a way, the result is exactly as the same as ListView, the original animation that had isn't "working", but that's because of how the implementation is done.</p>
  
  <h1><strong>Solution for the Animation</strong></h1>
  
  <p>The problem I had that was causing all the problems I talked above was actually because of LayoutAnimation, everytime I "deleted" a news feed with the filtering options the Layout Animation ended up deleting more than the news feed from the specific category.</p>
  
  <p>I apologize for this since I thought LayoutAnimation wasn't the problem and like that I didn't post that part of the code.</p>
  
  <p>Basically for this deleting problem doesn't occur, for now the solution is to make this:</p>
  
  <pre><code>LayoutAnimation.configureNext({
          duration: 300,
          create: {
              type: LayoutAnimation.Types.easeInEaseOut,
              property: LayoutAnimation.Properties.opacity,
          },
          update: { type: LayoutAnimation.Types.easeInEaseOut },
      });
  </code></pre>
  
  <p>If you are asking why I didn't put the delete, that's because in LayouAnimation delete doesn't work well on Android, only on iOS</p>
  
  <p>Again, sorry for wasting your time without putting all the information</p>