React Native Video因Zustand状态更新过度刷新致安卓性能下降崩溃
解决React Native中Zustand状态更新导致react-native-video过度刷新的问题
以下是针对你遇到的性能问题和安卓崩溃问题的具体优化方案:
一、精准订阅Zustand状态,减少不必要重渲染
Zustand默认会订阅整个store,任何状态更新都会触发组件重渲染。改为只订阅需要的字段,避免获取整个socialWallContents对象:
// 原代码 const { getSocialWallContent, socialWallContents } = useSocialWallStore((state) => state) // 修改后 const { getSocialWallContent, contents, loadingMore } = useSocialWallStore((state) => ({ getSocialWallContent: state.getSocialWallContent, contents: state.socialWallContents.contents, loadingMore: state.socialWallContents.loadingMore, }))
二、修复Memo组件的使用方式
你当前在组件内部创建SocialContentsMemo,每次父组件重渲染都会生成新的memo组件,完全失去缓存作用。把它移到组件外部:
// 移到import语句下方,组件定义之前 import SocialContents from '../../components/Recognition/Contents' const SocialContentsMemo = React.memo(SocialContents) const XXX = ({ props, route }) => { // ... 原有代码 }
同时用useCallback稳定onDelete函数的引用,避免触发子组件不必要重渲染:
import { useCallback } from 'react' const XXX = ({ props, route }) => { const onDelete = useCallback((itemId) => { // 你的删除逻辑 }, [/* 依赖项:比如store中的删除方法 */]) // ... 其他代码 }
三、优化FlashList的数据处理
1. 缓存排序后的数组
sort方法会返回新数组,每次重渲染都会生成新引用,导致FlashList全量重渲染。用useMemo缓存排序结果:
const wallData = useMemo(() => { if (!contents) return [] // 先复制数组再排序,避免修改原数据 return [...contents].sort((a, b) => Date.parse(b.dateCreatedUtc) - Date.parse(a.dateCreatedUtc)) }, [contents])
2. 不要用index作为key
用item的唯一ID替代index作为keyExtractor,确保列表项顺序变化时组件能正确复用:
<FlashList // ... 其他属性 keyExtractor={(item) => item.id.toString()} // 替换为你的item唯一ID字段 renderItem={({ item }) => ( <SocialContentsMemo data={item} onDelete={onDelete} /> // 移除多余的包裹View,减少层级 )} />
四、优化视频组件的渲染逻辑
1. 缓存媒体格式判断结果
每次重渲染都会重复判断视频格式,用useMemo缓存结果:
const SocialContents = ({ data, onDelete }) => { const [isBuffered, setIsBuffered] = useState(false) const isVideo = useMemo(() => { if (!data?.mediaUrl) return false const videoFormats = ['.mp4', '.webm', '.avi', '.mov', '.mkv', '.flv'] return videoFormats.some(format => data.mediaUrl.endsWith(format)) }, [data?.mediaUrl]) // ... 其他代码 }
2. 给视频添加缓存策略(安卓)
通过cacheKey属性让安卓端缓存相同视频,避免重复加载:
<Video source={{ uri: data.mediaUrl }} cacheKey={data.mediaUrl} // 用视频URL作为缓存标识 style={{ width: '100%', height: 200 }} resizeMode="contain" controls={isBuffered} paused={true} shouldPlay={false} // 明确初始不播放,减少不必要加载 onLoad={() => setIsBuffered(true)} />
五、其他布局优化
去掉FlashList父容器的固定宽高,改用flex:1自适应布局,避免布局计算错误引发的重渲染:
// 原代码 <View style={{ height: Dimensions.get("screen").height, width: Dimensions.get("screen").width, }} > <FlashList ... /> </View> // 修改后 <View style={{ flex: 1 }}> <FlashList ... /> </View>
给FlashList设置合理的固定estimatedItemSize(比如400),帮助组件更好地预估布局,减少滚动时的重渲染。
内容的提问来源于stack exchange,提问作者user20951184
相关产品推荐
相关产品推荐

