【问题标题】:PureComponent FlatList not re-rendering even when using extraData={this.state}即使使用 extraData={this.state},PureComponent FlatList 也不会重新渲染
【发布时间】:2019-04-01 05:48:02
【问题描述】:

经过一些研究,我似乎需要使用 PureComponent 而不是常规组件来提高我的 FlatList 的速度。这样它就不会重新渲染整个列表,只会重新渲染被更改的行。但是,当我这样做时,平面列表不会重新呈现。

这个问题How to re-render flatlist? 和其他类似的问题表明我必须在我的FlatList 中使用extradata={this.state},以便它可以查看数据源中是否发生了任何数据更改但它不起作用

我尝试过 this.state、this.state.symbols,尝试使用布尔值并在我的 onPress 函数中强制更改它,但似乎没有任何效果。

我将列表项从渲染函数中移到外部 js 文件中的自己的类中

export default class MyListItem extends React.PureComponent {
    render() {
        const { item } = this.props;
        return (
            <View style={{flex: 1, flexDirection: 'row'}}>
                <View style={{backgroundColor: 'powderblue'}}>
                    <Ionicons style={styles.listItemIcon} name={item.iconName} />
                </View>
                <View style={{backgroundColor: 'skyblue'}}>
                    <Text style={styles.listItem}>
                        {item.coinName.toUpperCase()} {item.symbol}
                    </Text>
                </View>
            </View>
        );
    };
}

我的 renderListItem 函数现在看起来像这样

renderListItem = ({ item , index}) => {
        return(
            <TouchableOpacity
                onPress={() => this.onPressListItem(index)}
            >
            <MyListItem
            item={item}
            />
            </TouchableOpacity>
        )
    }

这是 onPress 函数。正如你所看到的,这里的状态发生了变化,所以不知道为什么extraData 没有看到

onPressListItem = ( index ) => {
        const copyOfSymbolsList = [...this.state.symbols];
        thePressedSymbol = copyOfSymbolsList[index];

        if (thePressedSymbol.iconName === 'md-star') {
            thePressedSymbol.iconName = 'md-star-outline';
        }else{
            thePressedSymbol.iconName = 'md-star';
        }
        copyOfSymbolsList[index] = thePressedSymbol;

        this.setState({ 
            symbols: copyOfSymbolsList
        });

    }

这是我的平面列表

<FlatList
                    data={this.state.symbols}
                    extraData={this.state.symbols}
                    keyExtractor= {(item, index) => item.symbol}
                    ItemSeparatorComponent={this.renderListSeparator}
                    renderItem={this.renderListItem}
                />

【问题讨论】:

  • 你试过forceUpdate()吗?
  • @zoonosis PureComponent 只期望简单的状态......以便比较正常工作......
  • 如果您使用 lodash 深度克隆数组并尝试 const copyOfSymbolsList = _.cloneDeep(this.state.symbols);
  • @HendEl-Sahli 不确定您所说的简单状态是什么意思

标签: javascript node.js react-native expo


【解决方案1】:

您可能需要像这样在onPressListItem 函数中操作thePressedSymbol

onPressListItem = ( index ) => {
        const copyOfSymbolsList = [...this.state.symbols];
        thePressedSymbol = {
          ...copyOfSymbolsList[index],
          iconName: copyOfSymbolsList[index].iconName === 'md-star' ? 'md-star-outline' : 'md-star';
        }
        copyOfSymbolsList[index] = thePressedSymbol;

        this.setState({ 
            symbols: copyOfSymbolsList
        });

    }

这是因为在Javascript 中,Object 是reference 类型。你可以在控制台试试这个

var person1={
  name: 'John',
  age: 10
}
var person2 = person1;
console.log(person1===person2); // output: true
person2.age = 20;
console.log(person1===person2); // output: true
console.log(person1.age, person2.age); // output: 20 20

var person3 = {...person1};
console.log(person1===person3}; // output: false

这意味着,为了使 FlatList 重新渲染,您需要传递一个全新的 symbol 项目来替换数组中的现有项目(这是我上面的解决方案所做的);或者(我没有尝试过)你也可以实现自己的FlatList 组件来进行深度比较而不是浅层比较。

【讨论】:

  • 非常感谢@wicky 所以基本上,不是只更改 json 数组的 iconName 部分,而是用相同的数据重写该行的全部内容(新的 iconName 除外) .似乎不得不做所有这些都是浪费,但它确实有效。
  • 不客气。是的,绕过 FlatList 的肤浅比较似乎是一种“黑客”。但 IMO 是一个更好的解决方案,而不是必须在 FlatList 上进行自己的深度比较;)
猜你喜欢
  • 1970-01-01
  • 2018-12-26
  • 2018-07-08
  • 1970-01-01
  • 2019-09-05
  • 2019-07-28
  • 2020-02-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多