【问题标题】:How to prevent FlatList re rendering when state changes状态变化时如何防止 FlatList 重新渲染
【发布时间】:2021-02-22 19:02:04
【问题描述】:

我有一个非常大的 FlatList,它呈现 800 个带有图像和文本的按钮。此列表位于 TabScreen 内,该 TabScreen 位于主屏幕内,另一个 tabScreen 具有文本输入。当我更改此 textInput 中的文本时,setState 会触发我的平面列表,该列表在后台更新,再次呈现其大量项目并减慢一切。我怎样才能避免这种情况?

主屏幕:

export default function HomeScreen(props: any) {
  const Tab = createBottomTabNavigator();

  return (
    <View style={styles.home__container}>
      <HeaderButton navigation={props.navigation} />
      <Tab.Navigator
        screenOptions={({ route }) => ({
          tabBarIcon: ({ focused, color, size }) => {
            let iconName: string = "";
            if (route.name === "Search") {
              iconName = "ios-search";
            } else if (route.name === "List") {
              iconName = focused ? "ios-list-box" : "ios-list";
            }
            return <Ionicons name={iconName} size={size} color={color} />;
          },
        })}
        tabBarOptions={{
          activeTintColor: "#ffcb05",
          inactiveTintColor: "#ffffff",
          style: { backgroundColor: "#2a75bb" },
        }}
      >
        <Tab.Screen name="Search" component={TabSearchScreen} />
        <Tab.Screen  name="List" component={TabListScreen} />
      </Tab.Navigator>
      <PokemonSavedContainer navigation={props.navigation} />
    </View>
  );
}

平面列表选项卡(TabListScreen):

const TabListScreen = () => {
  const flatListRef = useRef<FlatList<{ name: string }>>(null);
  const scrollList = (index: number) => {
    if (flatListRef.current)
      flatListRef.current.scrollToIndex({ index: index });
  };
  const keyExtractor = (item: any) => `key-${item.name}`;
  const renderItem = (item: any) => {
    return (
      <MySwipeable pokeNumber={item.index + 1} pokeName={item.item.name} />
    );
  };
  return (
    <View style={styles.pokedex__list}>
      <FlatList
        data={pokedex}
        ref={flatListRef}
        renderItem={renderItem}
        keyExtractor={(item) => keyExtractor(item)}
        style={styles.pokedex__list__pokemons}
        onScrollToIndexFailed={() => alert("something went wrong")}
        getItemLayout={(data, index) => ({
          length: 100,
          offset: 100 * index,
          index,
        })}
      />
      <View style={{ flexDirection: "column", marginTop: 20 }}>
        <SmallButton onPress={() => scrollList(0)} title="Kanto" />
        <SmallButton onPress={() => scrollList(151)} title="Jhoto" />
        <SmallButton onPress={() => scrollList(251)} title="Hoenn" />
        <SmallButton onPress={() => scrollList(386)} title="Sinnoh" />
        <SmallButton onPress={() => scrollList(494)} title="Unova" />
        <SmallButton onPress={() => scrollList(649)} title="Kalos" />
        <SmallButton onPress={() => scrollList(721)} title="Alola" />
        <SmallButton onPress={() => scrollList(809)} title="Galar" />
      </View>
    </View>
  );
};
export default TabListScreen;

textInput 屏幕(TabSearch 屏幕):

export default function TabSearchScreen() {
  const pokemonState = useSelector((state: RootStore) => state.pokemon);

  return (
    <View style={styles.home__container}>
      <Searchbar />
      {pokemonState.pokemon && <PokeContainer />}
    </View>
  );
}

搜索组件

export default function Searchbar() {
  const dispatch = useDispatch();
  const handleSubmit = () => {
    dispatch(GetPokemon(pokemonName));
  };
  const [pokemonName, setPokemonName] = useState("");

  return (
    <View style={styles.home__search}>
      <TextInput
        style={styles.home__search__textInput}
        onChangeText={(value) => setPokemonName(value)}
        value={pokemonName}
      />
      <PokeBallButton title="search" onPress={handleSubmit} />
    </View>
  );
}

FlatList 项目(称为 Myswipeable,因为我想赋予它滑动功能)

export interface MySwipeProps {
  children?: React.ReactNode;
  props?: any;
  pokeName: string;
  pokeNumber: number;
}
const MySwipeable: React.FC<MySwipeProps> = ({
  children,
  pokeName,
  pokeNumber,
  ...props
}) => {
  console.log("pokemon");
  const renderLeftActions = () => {
    return <Animated.View></Animated.View>;
  };

  return (
    <Swipeable renderLeftActions={renderLeftActions}>
      <View style={styles.button__list__container}>
        <Image
          source={{
            uri: `https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/${pokeNumber}.png`,
          }}
          style={styles.pokemonTiny}
        />
        <Text style={styles.button__list__text}>{pokeName}</Text>
      </View>
    </Swipeable>
  );
};

export default MySwipeable;

【问题讨论】:

    标签: typescript react-native react-redux react-native-flatlist use-state


    【解决方案1】:

    尝试使用 React.memo() 来防止您的平面列表重新呈现。

    这是一篇有用的文章,解释了 React.memo() 是什么以及如何使用它。

    prevent-re-renders-react-functional-components-react-memo

    【讨论】:

    • 感谢您的帮助!我使用了备忘录,情况有所改善。我把 MySwipeable 变成了一个备忘录组件,现在我明白了问题不是状态变化,而是键盘打开!有了备忘录,每次我关闭 android 键盘(使用后退按钮和回车按钮)时,平面列表都会呈现其项目。如果我不使用备忘录,flatlist 会呈现键盘打开或关闭的所有项目。这让我很生气。我认为键盘与整个屏幕的渲染有关
    猜你喜欢
    • 2022-11-12
    • 2020-04-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-02
    • 1970-01-01
    • 2020-07-25
    • 1970-01-01
    相关资源
    最近更新 更多