React路由跳转返回后已memo化的FlatList列表项重复重渲染如何解决?
问题根因
你遇到的异常重渲染(包含组件重新挂载场景)主要由3个问题导致:
- 路由配置写法错误,跳转到详情页返回后整个首页组件直接重新挂载,所有子组件必然重新执行渲染逻辑
- FlatList的
renderItem为内联箭头函数,每次渲染时引用都会更新,触发FlatList全量重渲染行组件 - SingleRow组件本身存在写法错误,且props包含不稳定的引用类型,导致
React.memo浅比较不通过
修复步骤
1. 修正路由配置
如果使用的是React Router v5,禁止直接给component属性传JSX,否则每次路由匹配都会生成新的组件实例,正确写法如下:
// React Router v5 正确写法,传组件引用而非实例 <Route path="/" component={Screen1}/> <Route path="/detail" component={Screen2}/> <Route path="/about" component={Screen3}/>
如果使用的是React Router v6,element属性本身支持传JSX,不会触发重复挂载,不需要修改本条。
2. 稳定FlatList相关配置的引用
将内联的renderItem和keyExtractor提取到组件外部,用useCallback包裹保证引用稳定:
// Screen1.js 内部修改 import { useCallback } from 'react'; const Screen1 = (props) => { // 稳定renderItem引用 const renderItem = useCallback(({ item }) => { // 修正之前的拼写错误:SinleRowMemo → SingleRowMemo return <SingleRowMemo item={item} SomeFuncComesFromProps={props.someFunc} /> }, [props.someFunc]); // 稳定keyExtractor引用,必须设置key才能让FlatList正确复用行 const keyExtractor = useCallback((item) => item.id, []); return ( <FlatList data={props.cars.results} renderItem={renderItem} keyExtractor={keyExtractor} /> ) }
3. 修正SingleRow组件写法,优化memo比较逻辑
首先修正组件参数错误、属性匹配错误,再稳定onPress函数引用,还可以自定义memo的比较逻辑提升命中率:
// SingleRow.js 内部修改 import { useCallback } from 'react'; // 修正参数写法:之前的(props.item)是错误的,应该接收整个props export const SingleRow = (props) => { // 稳定onPress引用 const handlePress = useCallback(() => { props.SomeFuncComesFromProps(); }, [props.SomeFuncComesFromProps]); return ( <TouchableOpacity onPress={handlePress}> <View> {/* 修正属性匹配:之前传的是item={item},所以用props.item而非props.car */} <Text>{props.item.brand}</Text> </View> </TouchableOpacity> ) } // 自定义memo比较逻辑,只有必要属性变化时才重渲染 export const SingleRowMemo = React.memo(SingleRow, (prevProps, nextProps) => { return prevProps.item.id === nextProps.item.id && prevProps.SomeFuncComesFromProps === nextProps.SomeFuncComesFromProps });
4. 可选:增加路由缓存
如果需要保留页面跳转前的滚动位置、表单输入等状态,可以用路由缓存组件包裹首页组件,避免跳转时组件被销毁。
内容的提问来源于stack exchange,提问作者C D
相关产品推荐
相关产品推荐

