当道具更改时,React-native FlatList 不会重新渲染行

新手上路,请多包涵

我在使用新的 FlatList 组件时遇到问题。具体来说,它不会重新呈现它的行,即使该行依赖于更改的道具。


FlatList 文档说:

这是一个 PureComponent,这意味着如果 props 保持浅相等,它将不会重新渲染。确保您的 renderItem 函数所依赖的所有内容都作为更新后不是 === 的道具传递,否则您的 UI 可能不会在更改时更新。这包括数据道具和父组件状态。

问题

但是,当我更改 selectedCategory 项目的 ID 时——应该指示该行是否被“选中”的道具——我相信道具应该重新呈现。我弄错了吗?

我检查了列表和行组件的“componentWillReceiveProps”方法,列表接收到更新就好了,但从不调用行的生命周期方法。

如果我在列表组件中包含一个随机的、无用的布尔状态值,并在道具更新时来回切换它,它可以工作 - 但我不知道为什么?

 state = { updated: false };

componentWillReceiveProps(nextProps) {
  this.setState(oldstate => ({
    updated: !oldstate.updated,
  }));
}

<FlatList
  data={this.props.items.allAnimalCategories.edges}
  renderItem={this._renderRow}
  horizontal={true}
  keyExtractor={(item, index) => item.node.id}
  randomUpdateProp={this.state.updated}
/>


编码

我的代码结构是这样的:我有一个包含所有逻辑和状态的容器组件,其中包含一个 FlatList 组件(展示,无状态),它又包含一个自定义展示行。

 Container
  Custom list component that includes the FlatList component
  (presentational, stateless) and the renderRow method
    Custom row (presentational, stateless)

容器包括这个组件:

  <CustomList
   items={this.props.viewer}
   onCategoryChosen={this._onCategoryChosen}
   selectedCategory={this.state.report.selectedCategory}
 />

自定义列表:

 class CustomList extends Component {
  _renderRow = ({ item }) => {
    return (
      <CustomListRow
        item={item.node}
        selectedCategory={this.props.selectedCategory}
        onPressItem={this.props.onCategoryChosen}
      />
    );
  };

  render() {
    return (
      <View style={_styles.container}>
        <FlatList
          data={this.props.items.categories.edges}
          renderItem={this._renderRow}
          horizontal={true}
          keyExtractor={(item, index) => item.node.id}
          randomUpdateProp={this.state.updated}
        />
      </View>
    );
  }

}

(数据来自Relay)

最后一行:

 render() {
    const idsMatch = this.props.selectedCategory.id == this.props.item.id;
    return (
      <TouchableHighlight onPress={this._onItemPressed}>
        <View style={_styles.root}>
          <View style={[
              _styles.container,
              { backgroundColor: this._getBackgroundColor() },
            ]}>
            {idsMatch &&
              <Image
                style={_styles.icon}
                source={require('./../../res/img/asd.png')}
              />}
            {!idsMatch &&
              <Image
                style={_styles.icon}
                source={require('./../../res/img/dsa.png')}
              />}
            <Text style={_styles.text}>
              {capitalizeFirstLetter(this.props.item.name)}
            </Text>
          </View>
          <View style={_styles.bottomView}>
            <View style={_styles.greyLine} />
          </View>
        </View>
      </TouchableHighlight>
    );
  }

该行并不那么有趣,但我将其包括在内以表明它完全是无状态的并且依赖于它的父母道具。

状态更新如下:

 _onCategoryChosen = category => {
    var oldReportCopy = this.state.report;
    oldReportCopy.selectedCategory = category;
    this.setState(Object.assign({}, this.state, { report: oldReportCopy }));
  };

状态如下所示:

 state = {
    ...
    report: defaultStateReport,
  };

const defaultStateReport = {
  selectedCategory: {
    id: 'some-long-od',
    name: '',
  },
  ...
};


原文由 jhm 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 712
1 个回答

这里的问题在于

  1. 您正在更改现有的状态切片,而不是创建变异副本

_onCategoryChosen = category => {
    var oldReportCopy = this.state.report; // This does not create a copy!
    oldReportCopy.selectedCategory = category;
    this.setState(Object.assign({}, this.state, { report: oldReportCopy }));
};

这应该是

_onCategoryChosen = category => {
    var oldReportCopy = Object.assign({}, this.state.report);
    oldReportCopy.selectedCategory = category;
    // setState handles partial updates just fine, no need to create a copy
    this.setState({ report: oldReportCopy });
};


  1. FlatList 的道具保持不变,您的 _renderRow 函数可能依赖 selectedCategory 确实发生变化的道具(如果不是第一个错误),但 FlatList 组件不知道这一点.要解决此问题,请使用 extraData 道具。
     <FlatList
      data={this.props.items.categories.edges}
      renderItem={this._renderRow}
      horizontal={true}
      keyExtractor={(item, index) => item.node.id}
      extraData={this.props.selectedCategory}
    />

原文由 Nimelrian 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题