React Native中createSelector导致滚动时重复渲染的问题排查
问题原因分析
- createSelector参数顺序完全错误:你定义的
getPostsForFeed选择器中,输入选择器数组是[getFeeds, getPosts, getAccounts],但回调函数第一个参数写的是feedId——回调参数顺序必须和输入选择器的返回值顺序严格对应,所以第一个参数实际是feeds对象,而非你传入的feedId,直接导致后续逻辑全部偏离预期。 - 数据处理逻辑无效:用
forEach遍历postsArr时,循环内返回的合并account的对象并未被收集,最后返回的还是未合并账号信息的原始postsArr,完全没实现关联账号的需求。 - 选择器返回新引用触发重选:每次组件重渲染(比如
viewableIndexes更新时),选择器都会执行filter生成新数组引用。shallowEqual会比较数组引用是否相同,新引用不等于旧引用,所以useSelector判定posts发生变化,触发useEffect。
修复方案
1. 修正createSelector的参数与逻辑
把feedId对应的选择器加入输入数组,调整参数顺序,同时用map替代forEach正确生成合并账号的数组:
const getFeedId = (state, feedId) => feedId; const getFeeds = state => state.postsState.feeds; const getPosts = state => state.postsState.posts; const getAccounts = state => state.postsState.accounts; const getPostsForFeed = createSelector( [getFeedId, getFeeds, getPosts, getAccounts], // 将feedId选择器放在首位 (feedId, feeds, posts, accounts) => { const postIds = feeds[feedId] || []; // 增加默认值避免空引用报错 // 用filter筛选目标post,再用map合并对应账号信息 return posts .filter(post => postIds.includes(post.postId)) .map(post => { const account = accounts.find(acc => acc.accountId === post.accountId); return { ...post, account: account || {} // 增加默认值避免undefined }; }); } );
2. 优化组件内代码
- 移除多余的
memoizedPosts,useSelector结合shallowEqual已经做了缓存处理,直接传递posts即可。 - 修正FlashList的属性名:官方API是
renderItem而非renderItems,data而非items,错误属性名可能引发额外渲染问题。
修正后的组件代码片段:
const posts = useSelector(state => getPostsForFeed(state, 'home'), shallowEqual); const renderItem = useCallback(({item}) => { return (<Post item={item} />); }, []); const keyExtractor = useCallback(item => item.postId.toString(), []); const [viewableIndexes, setViewableIndexes] = useState([]); const onViewableItemsChanged = useCallback(({viewableItems}) => { setViewableIndexes(viewableItems.map(e => e.index)); }, []); <FlashList keyExtractor={keyExtractor} renderItem={renderItem} data={posts} onViewableItemsChanged={onViewableItemsChanged} />
3. 确保选择器记忆化生效
createSelector本身会缓存计算结果,只有当输入选择器的返回值变化时才会重新计算。要保证:
- 输入选择器返回Redux状态中的原始引用(不要在输入选择器里生成新数组/对象)
- 输出的合并数组仅在输入数据变化时才生成新引用
内容的提问来源于stack exchange,提问作者Sam Leurs
相关产品推荐
相关产品推荐

