状态更改时如何防止FlatList重新呈现

时间:2020-11-10 19:42:04

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

我有一个非常庞大的FlatList,其中包含800个带有图像和文本的按钮。此列表位于TabScreen内部,该TabScreen位于主屏幕中,而另一个tabText具有文本输入。当我在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>
  );
}

FlatList标签(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;

文本输入屏幕(标签搜索屏幕):

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;

1 个答案:

答案 0 :(得分:0)

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

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

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