当道具改变时,React-native FlatList不会重新呈现行 [英] React-native FlatList not rerendering row when props change

查看:71
本文介绍了当道具改变时,React-native FlatList不会重新呈现行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm having an issue with the new FlatList component. Specifically, it does not rerender it's rows, even though props that the row is dependent on changes.

FlatList文档说:

The FlatList docs says that:

这是一个PureComponent,表示如果出现以下情况,它将不会重新渲染 道具保持浅薄相等.确保所有内容都为renderItem 函数依赖于更新后作为不是===的prop传递, 否则,您的用户界面可能不会更新更改.这包括数据 属性和父组件状态.

This is a PureComponent which means that it will not re-render if props remain shallow- equal. Make sure that everything your renderItem function depends on is passed as a prop that is not === after updates, otherwise your UI may not update on changes. This includes the data prop and parent component state.

问题

但是,看到我更改了selectedCategory项目的ID(该道具应该指示是否已选中该行)时,我认为该道具应该重新显示.我误会了吗?

However, seeing as I change an ID of the selectedCategory item - the prop that should indicate whether the row is 'selected' or not - I believe that the props should rerender. Am I mistaken?

我检查了列表和行组件的'componentWillReceiveProps'方法,列表很好地接收了更新,但是从不调用行的生命周期方法.

I checked the 'componentWillReceiveProps' methods of both the list and row components, and the list receives the update just fine, but the row's lifecycle method is never called.

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

If I include a random, useless boolean state value in the list component, and switch it back and forth when the props update, it works - but I don't know why?

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组件(表示形式,无状态),它又包含一个自定义表示行.

The structure of my code is this: I have a container component with all the logic and state, which contains a FlatList component (presentational, no state), which again contains a custom presentational row.

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}
 />

CustomList:

CustomList:

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>
    );
  }

}

(数据来自中继)

最后一行:

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>
    );
  }

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

The row is not that interesting, but I included it to show that it is entirely stateless and dependent on it's parents props.

状态更新如下:

_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: '',
  },
  ...
};


推荐答案

这里的问题在于以下事实

The problem here lies within the fact that

  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 道具.

  1. The props of FlatList remain the same, your _renderRow function may rely on the selectedCategory prop which does change (If not for the first mistake), but the FlatList component does not know about that. To solve this, use the extraData prop.

<FlatList
  data={this.props.items.categories.edges}
  renderItem={this._renderRow}
  horizontal={true}
  keyExtractor={(item, index) => item.node.id}
  extraData={this.props.selectedCategory}
/>

这篇关于当道具改变时,React-native FlatList不会重新呈现行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆