如何记忆从 redux useSelector 派生的变量?

How can I memoize a variable derived from redux useSelector?

我怎样才能记住我的 rawTranscript 变量,这样它就不会触发下面的 useEffect 而随后会触发昂贵的 transcriptParser 函数?我一直在尝试很多不同的方法,但事实上我正在使用 redux-hook (useAppSelector) 从商店捕获数据意味着我不能使用空的依赖项 useEffect 进行初始挂载(hooks不能在 useEffect 内)。出于同样的原因,我似乎也无法用 useMemo 包装 useAppSelector

有没有想过如何记忆 rawTranscript 变量,这样它就不会重新触发 useEffect

useMemouseEffectuseCallback 中使用 redux-hook 时出错:

React Hook "useAppSelector" cannot be called inside a callback. React Hooks must be called in a React function component or a custom React Hook function.

分量

const TranscriptCardController = (): JSX.Element => {
  const dispatch = useAppDispatch();
  // how to memoize rawTranscript?
  const rawTranscript = useAppSelector(selectRawTranscript);
  const parsedTranscript = useAppSelector(selectParsedTranscript);

  useEffect(() => {
    const parsedResult = transcriptParser(rawTranscript, undefined, 0.9);
    dispatch(updateParsedTranscript(parsedResult));
  }, [dispatch, rawTranscript]);

  // ...
};

选择器

export const selectRawTranscript = createSelector(
  (state: RootState) => state.transcript.rawTranscript,
  (rawTranscript): RawTranscript => rawTranscript
);

创建一个独立的 useCallback,您的分派将在每次 store 更新时 运行,但 useEffect 仅在执行 callback 方法时执行。

const TranscriptCardController = (): JSX.Element => {
  const dispatch = useAppDispatch();
  // how to memoize rawTranscript?
  const rawTranscript = useAppSelector(selectRawTranscript);
  const parsedTranscript = useAppSelector(selectParsedTranscript);
  
  const callback = useCallback(() => {
    const parsedResult = transcriptParser(rawTranscript, undefined, 0.9);
    dispatch(updateParsedTranscript(parsedResult));
  }, [rawTranscript])


  useEffect(() => {
    const unsubscribe = callback()

    return unsubscribe
  }, [callback]);

  // ...
};

如果您的 selectRawTranscript 函数纯粹是从商店中选择一个值,例如 state => state.transcript.raw,这里没有问题。只有当 rawTranscript 的值发生变化时,您的效果才会 运行 -- 这是应该的。

如果你的 selectRawTranscript 函数 returns 每次都是一个新对象(如果它涉及数组映射等,就喜欢它)那么这是一个你可以在选择器本身或在组件中。


记忆选择器

解决此问题的最佳方法是使用 createSelector 创建一个备忘的选择器。例如:

import {createSelector} from '@reduxjs/toolkit';

export const selectRawTranscript = createSelector(
  (state: RootState) => state.data.someRawValue,
  (rawValue) => rawValue.map(entry => entry.data)
);

选择器的第二部分是“组合器”,只有当第一部分选择的值改变时,它才会重新运行。所以你得到了一个一致的对象引用。


平等比较

如果你想在组件中解决这个问题,方法是在 useAppSelector 上包含第二个参数(我假设它只是 useSelector 的类型化版本) .

第二个参数允许您指定 custom equality function 以便您可以更好地控制所选数据何时被视为“已更改”。使用浅层相等比较很常见,所以这实际上包含在 react-redux 包中。

import { shallowEqual } from 'react-redux';
import { useAppSelector } from ...

const TranscriptCardController = (): JSX.Element => {
  const rawTranscript = useAppSelector(selectRawTranscript, shallowEqual);
...

注意:我无法知道您是否真的对 rawTranscript 中的不良更改存在问题,因为您没有包含选择器函数。您可能想多了,这可能不是问题。