reactjs 优化自定义钩子的返回值以防止重新呈现

bf1o4zei  于 2023-08-04  发布在  React
关注(0)|答案(2)|浏览(65)

想象一下,我有一些自定义钩子,我从上下文(某种我自己的存储)中提取一些值

// example of state structure

function GlobalComponent(){
 const initialState = {
   reports: {depositReport: []},
   users: [],
 }

 const [state, dispatch] = useReducer(reducer, initialState)

 return <StoreContext.Provider value={{state}}></State.Provider>
}

个字符
这是我如何使用这个钩子的例子

function Component() {
 const { depositReport } = useSelector(state => state.reports);
}


当我通过Component中的示例从状态中提取depositReport值时,每当state对象中的任何属性发生变化时,它都会重新呈现。但是我如何才能优化useSelector钩子,重新渲染组件时,它只使用特定值state => state.reports才会改变。
检查codesandbox上的示例,你会看到当我改变users属性时,它会重新渲染我只提取reports.depositReport但我想要优化useSelector钩子的地方,它只会在我提取值时重新渲染我想要对的改变做出React


的数据

wztqucjr

wztqucjr1#

这是不可能的。它使用在每次渲染时更改值的上下文。如果该值更改,则使用useContext(StoreContext)的每个子组件都会重新渲染。没有办法防止这种情况发生。
您可以使用第三方库,如use-context-selector或创建自己的商店。它并不像仅仅调用useContext那么简单

a11xaf1n

a11xaf1n2#

因此,基于提供的沙箱,我能够找到两个关键的地方,你可以减少不必要的重新渲染:

  • useSelector函数
  • 要订阅状态的Users组件

以下是已实施的更改:

const useSelector = (callback) => {
  const { state } = useContext(StoreContext);
  return useMemo(() => callback(state), [callback, state]);
};

字符串
在这里,如果回调函数或状态对象发生更改,则使用useMemo将重新计算状态的选定部分。然而,这要求您在从组件调用callback函数时将其 Package 在useCallback钩子中,因此更新了Users组件:

const Users = () => {
  const dispatch = useDispatch();
  const selectUsers = useCallback((state) => state.users, []);
  const users = useSelector(selectUsers);

  console.log(users, "users");
  return (
    <div>
      <button
        onClick={() => {
          const data_to_set = ["first", "second"];
          if (areArraysEqual(users, data_to_set)) return;
          dispatch({
            type: UsersE.SET_USERS,
            payload: {
              data: data_to_set
            }
          });
        }}
      >
        Change users
      </button>
    </div>
  );
};


areArraysEqual的定义:

function areArraysEqual(arr1, arr2) {
  if (arr1.length !== arr2.length) return false;
  const sortedArr1 = arr1.slice().sort();
  const sortedArr2 = arr2.slice().sort();

  for (let i = 0; i < sortedArr1.length; i++) {
    if (sortedArr1[i] !== sortedArr2[i]) {
      return false;
    }
  }

  return true;
}

相关问题