React Native 标签选择页面点击后出现数秒卡顿问题求助
问题原因
- 列表key使用
Math.random():每次组件重渲染时所有标签项的key都会完全重置,React会销毁整个标签列表再重新创建所有节点,而非增量更新,这是卡顿的核心原因。 - selected状态外置且使用数组存储:全局外置的selected不属于React状态管控,容易出现状态不同步问题,且数组的
includes、indexOf、splice操作都是O(n)复杂度,标签数量多的时候计算开销会大幅上升。 - 业务逻辑冗余错误:fire1、fire2两个函数逻辑混乱,取消选中的fire2中仍然执行了
setInterests([...interests, item])的新增逻辑,存在不必要的状态更新。 - 重复的组件声明:相同结构的PressableBackground写了两份,每次渲染都会生成大量重复的匿名函数,增加渲染开销。
解决方案
- 替换随机key:使用标签本身作为唯一固定key,确保React可以复用组件节点,避免全量销毁重建。
- 重构selected状态:将selected移入组件内部用useState管控,同时改为Set类型,将增删查的复杂度降到O(1)。
- 合并逻辑删除冗余:将两个点击函数合并为一个,修正选中/取消选中的状态更新逻辑,不需要的冗余状态可以直接删除。
- 封装单个标签组件:用React.memo封装单个标签项,结合useCallback缓存点击函数,只更新状态发生变化的标签,其他标签不重渲染。
优化后参考代码
import { useState, useCallback, memo } from 'react' // 封装单个标签组件,只有item、selected、onPress变化时才会重渲染 const TagItem = memo(({ item, selected, onPress, colors }) => { return ( <PressableBackground onPress={() => onPress(item)}> <View style={{margin: 2.5}}> <Tag color={selected ? colors.card : undefined}> <Text style={{color: selected ? colors.background : colors.text}}>{item}</Text> </Tag> </View> </PressableBackground> ) }) const TagScreen = () => { const [allInterests] = useState(["interst1", "interst2", "interst3", "interst4", "interst5", "interst6", "interst7", "interst8", "interst9", "interst10"]) // 用Set存储选中项,操作复杂度O(1) const [selected, setSelected] = useState(new Set()) // 如果后续不需要用到interests状态可以直接删除,这里保留兼容原有逻辑 const [interests, setInterests] = useState([]) const toggleTag = useCallback((item) => { setSelected(prev => { const newSelected = new Set(prev) if (newSelected.has(item)) { newSelected.delete(item) // 同步更新interests,不需要的话可以删掉这段逻辑 setInterests(prev => prev.filter(i => i !== item)) } else { newSelected.add(item) setInterests(prev => [...prev, item]) } return newSelected }) }, []) return ( <View> <View style={{display: "flex", flexWrap: "wrap", flexDirection: "row"}}> {allInterests.map(item => ( <View key={item}> <TagItem item={item} selected={selected.has(item)} onPress={toggleTag} colors={colors} /> </View> ))} </View> </View> ); } export default TagScreen;
内容的提问来源于stack exchange,提问作者Henrik
相关产品推荐
相关产品推荐

