You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 23:35:11