面试官:useSelector 返回的一个 state 数据很大,这个要怎么优化

开发
如果 useSelector 返回的 state 数据很大,可能会导致 不必要的组件重新渲染,影响性能。优化方式主要有以下几种。

如果 useSelector 返回的 state 数据很大,可能会导致 不必要的组件重新渲染,影响性能。优化方式主要有以下几种:

1. 精确选择数据,避免返回整个对象

错误做法(返回整个 state 对象):

const bigData = useSelector(state => state.bigData);

问题:任何 state.bigData 内部的字段变化都会触发组件重新渲染,即使组件只用到其中一部分数据。

正确做法(只选择需要的字段):

const someValue = useSelector(state => state.bigData.someValue);

优势:组件只会在 someValue 变化时重新渲染,而不会因 bigData 的其他字段变化而重新渲染。

2. 使用 reselect 进行 Memoization

如果计算 state 需要进行复杂的计算(如 filter、map 等),可以使用 reselect 缓存计算结果。

安装 reselect:

npm install reselect

创建 selector:

import { createSelector } from "reselect";

// 原始数据选择器
const selectBigData = state => state.bigData;

// 计算派生数据
export const selectFilteredData = createSelector(
  [selectBigData],
  bigData => bigData.filter(item => item.active) // 只返回 active 状态的数据
);

组件中使用 selector:

import { useSelector } from "react-redux";
import { selectFilteredData } from "./selectors";

const MyComponent = () => {
  const filteredData = useSelector(selectFilteredData);

  return <div>{filteredData.length}</div>;
};

优势:createSelector 只有在 state.bigData 变化时才会 重新计算,否则返回缓存结果。

避免不必要的计算,提升性能。

3. useSelector 第二个参数 equalityFn 自定义比较

默认情况下,useSelector 使用 浅比较(===) 来判断状态是否变化。如果 state 是 深层对象,可以使用 自定义比较函数 进行优化。

默认 useSelector(浅比较,可能会导致不必要的渲染):

const data = useSelector(state => state.bigData); // 任何字段变化都会重新渲染

使用 shallowEqual 进行浅层对比:

import { shallowEqual, useSelector } from "react-redux";

const data = useSelector(state => state.bigData, shallowEqual);

优势:shallowEqual 仅在 bigData 的 顶层字段 发生变化时才触发组件重新渲染。

自定义 equalityFn(仅在 id 变化时更新):

const selectedItem = useSelector(
  state => state.bigData.find(item => item.id === 1),
  (prev, next) => prev.id === next.id // 只在 id 变化时重新渲染
);

优势:避免 bigData 其他字段变化时,导致不必要的重新渲染。

4. 拆分 state,减少 store 更新影响范围

如果 bigData 很大,可以考虑拆分 store 结构,让 Redux 多个 slice 管理不同部分的数据。

优化前(单个 slice 存放大量数据):

const rootReducer = combineReducers({
  bigData: bigDataReducer
});

优化后(拆分成多个 slice):

const rootReducer = combineReducers({
  users: usersReducer,
  products: productsReducer
});

组件按需获取 state:

const users = useSelector(state => state.users);
const products = useSelector(state => state.products);

优势:避免 bigData 变化时,所有依赖 bigData 的组件都重新渲染。

5. 组件拆分,减少渲染范围

如果 useSelector 获取的数据很大,考虑 拆分组件,让子组件只订阅需要的数据。

错误示例(整个组件订阅大数据):

const ParentComponent = () => {
  const bigData = useSelector(state => state.bigData);

  return (
    <div>
      {bigData.map(item => (
        <p key={item.id}>{item.name}</p>
      ))}
    </div>
  );
};

优化示例(拆分成子组件,每个子组件独立订阅状态):

const ListItem = ({ id }) => {
  const item = useSelector(state => state.bigData.find(i => i.id === id));
  return <p>{item.name}</p>;
};

const ParentComponent = () => {
  const itemIds = useSelector(state => state.bigData.map(i => i.id));

  return (
    <div>
      {itemIds.map(id => (
        <ListItem key={id} id={id} />
      ))}
    </div>
  );
};

优势:只有受影响的 ListItem 组件会重新渲染,而不是整个 ParentComponent。

6. 结合 useMemo 进行优化

如果 useSelector 返回的数据需要复杂计算,可以用 useMemo 缓存结果,避免重复计算。

错误示例(计算逻辑直接在 useSelector 内部):

const filteredData = useSelector(state =>
  state.bigData.filter(item => item.active) // 每次都会重新计算
);

优化示例(用 useMemo 缓存计算结果):

const data = useSelector(state => state.bigData);
const filteredData = useMemo(() => data.filter(item => item.active), [data]);

优势:useMemo 只有在 data 变化时才会重新计算,提高性能。

总结

优化方法

思路

适用场景

1. 精确选择数据

useSelector

 只返回 需要的字段,而不是整个 state

适用于 state 体积大、变化频繁的情况

2. 使用 reselect

createSelector

 缓存计算结果,避免重复计算

适用于 依赖计算、列表过滤 场景

3. 自定义 equalityFn

只在 关键数据变化 时触发渲染

适用于 深层数据结构

4. 拆分 state

将 state 拆成多个 slice,减少 store 影响范围

适用于 大规模应用

5. 组件拆分

让子组件独立订阅 state,避免父组件无意义渲染

适用于 列表渲染、大数据量场景

6. useMemo 缓存计算

避免 useSelector 内部重复计算

适用于 复杂计算

最终优化思路:

  • 尽量让 useSelector 只选择最小数据。
  • 使用 reselect 避免不必要的计算。
  • 尽量拆分组件,减少不必要的渲染。

这样可以让 react-redux 更高效地更新 UI,提升应用性能!

责任编辑:赵宁宁 来源: 大迁世界
相关推荐

2017-03-16 15:27:10

面试官测试技术

2020-10-21 18:42:39

数据库数据库查询分页查询

2022-01-10 11:04:41

单链表面试编程

2022-04-08 08:26:03

JavaHTTP请求

2021-09-28 13:42:55

Chrome Devwebsocket网络协议

2023-01-15 17:57:12

缓存技术kafka磁盘

2020-05-13 14:35:47

HashMap面试官Java

2021-05-19 08:17:35

秒杀场景高并发

2023-07-31 08:26:09

2020-06-22 07:47:46

提交面试官订单

2022-08-18 20:02:04

JSLRU缓存

2021-06-09 07:55:19

NodeEventEmitte驱动

2021-03-24 10:25:24

优化VUE性能

2024-11-26 08:09:58

2024-05-28 10:14:31

JavaScrip模板引擎

2024-03-07 17:21:12

HotSpotJVMHot Code

2023-01-18 17:50:35

系统架构Kafka

2024-08-08 16:53:17

2018-10-22 14:28:26

面试官数据公司

2024-08-07 08:15:47

点赞
收藏

51CTO技术栈公众号