状态变化时如何防止 FlatList 重新渲染
Posted
技术标签:
【中文标题】状态变化时如何防止 FlatList 重新渲染【英文标题】:How to prevent FlatList re rendering when state changes 【发布时间】: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;
【问题讨论】:
【参考方案1】:尝试使用 React.memo() 来防止您的平面列表重新呈现。
这是一篇有用的文章,解释了 React.memo() 是什么以及如何使用它。
prevent-re-renders-react-functional-components-react-memo
【讨论】:
感谢您的帮助!我使用了备忘录,情况有所改善。我把 MySwipeable 变成了一个备忘录组件,现在我明白了问题不是状态变化,而是键盘打开!有了备忘录,每次我关闭 android 键盘(使用后退按钮和回车按钮)时,平面列表都会呈现其项目。如果我不使用备忘录,flatlist 会呈现键盘打开或关闭的所有项目。这让我很生气。我认为键盘与整个屏幕的渲染有关以上是关于状态变化时如何防止 FlatList 重新渲染的主要内容,如果未能解决你的问题,请参考以下文章