2

我怎样才能记住我的rawTranscript变量,这样它就不会触发useEffect下面的随后触发昂贵的transcriptParser函数?我一直在尝试很多不同的方法,但是我使用 redux-hook ( useAppSelector) 从存储中捕获数据的事实意味着我不能使用空依赖 useEffect 进行初始挂载(钩子不能在里面的使用效果)。出于同样的原因,我似乎也不useAppSelector能用 a来包装。useMemo

关于如何记忆rawTranscript变量的任何想法,因此它不会重新触发useEffect

useMemo在, useEffect,中使用 redux-hook 时出错useCallback

不能在回调中调用 React Hook “useAppSelector”。React Hooks 必须在 React 函数组件或自定义 React Hook 函数中调用。

零件

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
);
4

2 回答 2

2

如果您的selectRawTranscript函数纯粹是从商店中选择一个值,例如state => state.transcript.raw. 您的效果仅在值更改时才会运行rawTranscript- 应该如此。

如果您的selectRawTranscript函数每次都返回一个新对象(如果它涉及数组映射等),那么这是一个您可以在选择器本身或组件中解决的问题。


记忆选择器

解决此问题的最佳方法是使用createSelector创建记忆选择器。例如:

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

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

选择器的第二部分是“组合器”,它只会在第一部分中选择的值发生变化时重新运行。所以你得到一个一致的对象引用。


平等比较

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

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

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

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

注意:我不可能知道您是否真的对不希望的更改有问题,rawTranscript因为您没有包含您的选择器功能。你可能想多了,这可能不是问题。

于 2021-08-23T00:46:42.900 回答
0

创建一个独立的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]);

  // ...
};
于 2021-08-22T14:09:40.567 回答