React Native:为啥 FlatList 会在数据更改时完全重新渲染?

Posted

技术标签:

【中文标题】React Native:为啥 FlatList 会在数据更改时完全重新渲染?【英文标题】:React Native: Why does FlatList re-render completely on data changes?React Native:为什么 FlatList 会在数据更改时完全重新渲染? 【发布时间】:2020-12-10 19:24:56 【问题描述】:

感谢您阅读我的问题!几天以来,我一直在努力解决这个问题:每次更改基础数据时,我的 Flatlist 组件都会重新呈现列表中的所有项目。

情况:

我有一个 FlatList 组件呈现项目,其中包含一个 TouchableOpacity 对象来切换该项目的收藏状态。 如果按下此按钮,我希望在我的 FlatList 中仅更改/重新呈现此特定项目,而不是所有项目。感觉就像我通过调用 setListData 更新状态后,它会重新渲染所有内容。 我在更复杂的设置中遇到了这个问题,但能够深入研究这个核心问题。或者这实际上是预期的行为?

代码:

import React,  useState  from "react";
import 
  View,
  Text,
  StyleSheet,
  FlatList,
  TouchableOpacity,
 from "react-native";

const PlanerScreen = () => 
  const [listData, setListData] = useState([
     id: "1", name: "Banana", isFav: true ,
     id: "2", name: "Apple", isFav: false ,
  ]);

  const Item = ( item, onPressHandler ) => 
    console.log(item.name, " rendered");
    const color = item.isFav ? "red" : "green";
    return (
      <View
        style=
          flexDirection: "row",
          width: "100%",
          margin: 10,
        
      >
        <Text>item.name</Text>
        <TouchableOpacity
          style= width: 100, height: 50, backgroundColor: color 
          onPress=onPressHandler
        />
      </View>
    );
  ;

  const favHandler = (id) => 
    setListData(
      listData.map((item) =>
        item.id === id ?  ...item, isFav: !item.isFav  : item
      )
    );
  ;

  console.log("FlatList rendered");
  return (
    <View style= flex: 1 >
      <StatusBar style=selectedTheme === "light" ? "dark" : "light" />
      <FlatList
        data=listData
        renderItem=( item ) => (
          <Item item=item onPressHandler=() => favHandler(item.id) />
        )
        keyExtractor=(item) => item.id
      />
    </View>
  );
;

export default PlanerScreen;

点击收藏切换按钮时的控制台输出:

FlatList rendered
Banana  rendered
Apple  rendered
FlatList rendered
Banana  rendered
Apple  rendered
FlatList rendered
Banana  rendered
Apple  rendered

【问题讨论】:

您正在设置PlannerScreen 的状态,这反过来又重新渲染了整个FlatList。您应该问的问题是:- 重新渲染会影响您的性能吗? 确实如此,因为我在 FlatList 的每个项目中都有小缩略图,而 FlatList 包含 >100 个项目(在更复杂的上下文中)。在每次 stateChange 时,Items 中的所有图像都会由于重新渲染而闪烁。 【参考方案1】:

您可以使用React.memo 替代shouldComponentUpdate 的功能组件。 它告诉React 何时根据 prev 和 next 属性重新渲染组件。

import React,  useState  from "react";
import 
  View,
  Text,
  StyleSheet,
  FlatList,
  TouchableOpacity,
 from "react-native";

const styles = StyleSheet.create(
  container: 
    flex: 1,
  
)

const keyExtractor = (item) => item.id;

const Item = React.memo(( item, onPressHandler ) => 
  console.log(item.name, " rendered");
  const color = item.isFav ? "red" : "green";
  return (
    <View
      style=
        flexDirection: "row",
        width: "100%",
        margin: 10,
      
    >
      <Text>item.name</Text>
      <TouchableOpacity
        style= width: 100, height: 50, backgroundColor: color 
        onPress=() => onPressHandler(item.id)
      />
    </View>
  );
, (prevProps, nextProps) => 
  if (prevProps.item.isFav === nextProps.item.isFav) return true;
  return false;
);

const PlanerScreen = () => 
  const [listData, setListData] = useState([
     id: "1", name: "Banana", isFav: true ,
     id: "2", name: "Apple", isFav: false ,
  ]);

  const favHandler = (id) => 
    setListData(prevState => 
      return prevState.map((item) =>
          item.id === id ?  ...item, isFav: !item.isFav  : item
        )
      
    );
  


  console.log("### FlatList rendered #####");
  return (
    <View style=styles.container>
      <FlatList
        data=listData
        renderItem=( item ) => <Item item=item onPressHandler=favHandler />
        keyExtractor=keyExtractor
      />
    </View>
  );
;

export default PlanerScreen;

【讨论】:

谢谢,就像一个魅力!这正是我要找的,你刚刚拯救了我的周末:)

以上是关于React Native:为啥 FlatList 会在数据更改时完全重新渲染?的主要内容,如果未能解决你的问题,请参考以下文章

react-native ScrollView 嵌套 FlatList滚动

React Native之FlatList组件(一)

React Native - FlatList - 内部状态

在 React 中等效于来自 React Native 的 FlatList

FlatList vs map react-native

React Native FlatList 嵌套在具有相同方向的 FlatList 中