如何记忆从 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
?
在 useMemo
、useEffect
、useCallback
中使用 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
中的不良更改存在问题,因为您没有包含选择器函数。您可能想多了,这可能不是问题。
我怎样才能记住我的 rawTranscript
变量,这样它就不会触发下面的 useEffect
而随后会触发昂贵的 transcriptParser
函数?我一直在尝试很多不同的方法,但事实上我正在使用 redux-hook (useAppSelector
) 从商店捕获数据意味着我不能使用空的依赖项 useEffect 进行初始挂载(hooks不能在 useEffect 内)。出于同样的原因,我似乎也无法用 useMemo
包装 useAppSelector
。
有没有想过如何记忆 rawTranscript
变量,这样它就不会重新触发 useEffect
?
在 useMemo
、useEffect
、useCallback
中使用 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
中的不良更改存在问题,因为您没有包含选择器函数。您可能想多了,这可能不是问题。