React Native: ListView to re-render only selected item and not everything

Viewed 505

I have a ListView inside a Modal that renders data. When the user clicks on the item in that list, I want the check box to show next to that item to represent that item is selected. The bug I'm experiencing is that the UI doesn't reflect that actual selection. So when the user taps on an item, nothing changed, however when the modal is re-opened the UI displays the checkmark next to the previously selected item.

The fix I found for this is the force re-render using key in ListView. This is ok, but if I have images in the list they all flash because everything is being re-rendered. Without setting the key, it looks like my method renderItems is not called after a change (user selection). Leaving that key and adding keys to each render item does not seem to help either. How can I get the UI I expect without forcing a re-render for everything? Maybe I need to switch to FlatList to control individual list item's render?

Methods:

        constructor(props) {
         super(props);
         const ds = new ListView.DataSource({
           rowHasChanged: (r1, r2) => r1 !== r2,
         });
         this.state = {
           selected: this.parseSelected(props.data),
           selectedCached: null,
           dataSource: ds.cloneWithRows(props.data),
         };
        }

        componentWillReceiveProps = nextProps => {
        if (nextProps.visible) {
          const saved = this.state.selected;
          this.setState({
            selectedCached: saved,
          });
        }
      }; 

      getKey = selected => {
    switch (this.props.type) {
      case 'SHIPPING':
        return selected.code;
      case 'REASON':
        return selected;
      case 'MULTICARDS':
        return selected.account_token;
      default:
        return null;
    }
  };

  parseSelected = selected => {
    switch (this.props.type) {
      case 'SHIPPING':
      case 'REASON':
        return selected[0];
      case 'MULTICARDS':
        return selected[this.props.selectedProduct];
      default:
        return null;
    }
  };

  tempSaveSelection = selected => {
    this.setState({ selected });
  };

renderItems = item => {
    let selected;
    let body;
    let style;
    switch (this.props.type) {
      case 'SHIPPING':
        selected = this.state.selected.code === item.code;
        body = <ShipItem token={item} />;
        break;
      case 'REASON':
        selected = this.state.selected === item;
        body = <FormattedMessage id={`reason_${item}`} />;
        style = textSection;
        break;
      case 'MULTICARDS':
        selected = this.state.selected.account_token === item.account_token;
        body = <CardItem product={item} />;
        style = textSection;
        break;
      default:
        selected = false;
        body = null;
        style = null;
    }

Returning:

const { selected, dataSource } = this.state;
const selectedKey = this.getKey(selected);

   <ListView
      key={selectedKey}
      dataSource={dataSource}
      renderRow={this.renderItems}
    />
0 Answers
Related