考虑以下 React 组件:
interface Props {
cpi: number;
onCpiChange: (value?: number) => void;
}
const Assumption: FunctionComponent<Props> = (props: Props) => {
const [cpiValue, setCpiValue] = useState<number>();
useEffect(() => {
if (props.cpi != cpiValue) {
setCpiValue(props.cpi);
}
}, [props.cpi]);
return (
<FormattedNumberInput
value={cpiValue}
onBlur={() => props.onCpiChange(cpiValue)}
onValueChange={setCpiValue}
/>
);
};
export default Assumption;
useEffect
抱怨它缺少 cpiValue
- 由于它不在依赖数组中,因此在使用 props.cpi != cpiValue
进行比较时它不会更新。我不希望每次 useEffect
更改时都触发此 cpiValue
。我如何让这个 useEffect
仅在 props.cpi 更改但仍然可以访问所需的其他变量(例如与我进行比较的 cpiValue
)时做出响应?
此外,在最初学习 React Hooks 时,我了解到有多种方法可以控制 useEffect
何时触发,如下所示:
useEffect
都会触发。其中唯一有意义的是第三个选项。如果您不将它们包含在依赖数组中,则选项一和二对 useEffect
之外的变量没有作用域,但随后将所需变量添加到依赖数组会将 useEffect
的定义从1 或 2 到 3。我在这里遗漏了什么吗?
答案 0 :(得分:2)
您可以将条件测试移动到状态更新程序中,这应该将其作为依赖项删除。使用功能状态更新,您可以使用先前状态的 cpiValue
并使用三元返回新的 cpi
props value 或先前状态 cpiValue
值.
useEffect(() => {
setCpiValue(cpiValue => props.cpi !== cpiValue ? props.cpi : cpiValue);
}, [props.cpi]);
在我看来,我认为没有必要进行条件测试,因为似乎任何时候 props.cpi
更新并触发 useEffect
回调,您目前仅在更新不存在时才将更新排入队列t 已经等于当前状态。为什么不总是在更新时更新本地状态缓存的 props.cpi
版本?
useEffect(() => {
setCpiValue(props.cpi);
}, [props.cpi]);
如果它们实际上已经相等,那么它们之后仍然相等。如果值相同,React 可以 bail out of state updates。
<块引用>如果您将 State Hook 更新为与当前状态相同的值, React 将在不渲染子项或触发效果的情况下退出。 (React 使用 Object.is 比较算法。)
请注意,React 可能仍需要再次渲染该特定组件
在保释之前。这不应该是一个问题,因为 React 不会
不必要地“深入”到树中。如果你做的很贵
渲染时进行计算,您可以使用 useMemo
对其进行优化。
答案 1 :(得分:0)
useState
每次调用时都会触发重新渲染。并且更改的 props 也会触发组件重新渲染。
也许您可以使用 useState(initialize)
。
interface Props {
cpi: number;
onCpiChange: (value?: number) => void;
}
const Assumption: FunctionComponent<Props> = (props: Props) => {
const [cpiValue, setCpiValue] = useState<number>(props.cpi);
// useEffect(() => {
// if (props.cpi != cpiValue) {
// setCpiValue(props.cpi);
// }
// }, [props.cpi]);
return (
<FormattedNumberInput
value={cpiValue}
onBlur={() => props.onCpiChange(cpiValue)}
onValueChange={setCpiValue}
/>
);
};
export default Assumption;