考虑以下示例:
import React, { useCallback } from 'react';
type UserInputProps = {
onChange: (value: string) => void;
};
const UserInput = React.memo(({ onChange }: UserInputProps) => {
// Is this `useCallback` redundant?
const handleChange = useCallback(
(event) => {
onChange(event.target.value);
},
[onChange]
);
return <input type="text" onChange={handleChange} />;
});
export default UserInput;
我的问题是:
onChange
而没有其他元素时,在这种情况下useCallback
是不必要的,因为整个组件已经基于onChange
进行了记录吗? li>
value
的初始值是<input>
),那么我认为useCallback
会很有用,因为否则handleChange
将即使onChange
不变但value
也被重新创建。正确吗?答案 0 :(得分:8)
当道具仅包含
onChange
而没有其他元素时,在这种情况下useCallback
是不必要的,因为整个组件已经基于onChange
进行了记录吗?
它是基于所有道具而不仅仅是onChange
来记忆的。是的,useCallback
在那里是不需要的。
如果我们添加一个额外的道具(例如,
value
的初始值是<input>
),那么我认为useCallback
很有用,因为否则handleChange
将即使onChange
不变,但值已更改,也可以重新创建。正确吗?
如果您想在更新value
时更新onChange
而不更新input
,则可以在道具中添加value
并继续使用{{1} }作为useCallback
的名称(如果愿意,这样React可以在设置值时不必交换新的事件处理程序;我的印象是,这通常是过大的)。例如:
handleChange
这将使用最新的const UserInput = React.memo(({ onChange, value }: UserInputProps) => {
const handleChange = useCallback(
(event) => {
onChange(event.target.value);
},
[onChange]
);
return <input type="text" value={value} onChange={handleChange} />;
});
并在value
道具未更改的情况下重用先前的handleChange
。
在这种情况下,如果您期望onChange
由于React.memo
而被更改,则可能不会保留value
。也就是说,如果您希望常见的情况是每次调用您的组件时onChange
都会不同,那么value
对道具的检查就是您的额外工作可能不会保留:
React.memo
但是如果您希望const UserInput = ({ onChange, value }: UserInputProps) => {
const handleChange = useCallback(
(event) => {
onChange(event.target.value);
},
[onChange]
);
return <input type="text" value={value} onChange={handleChange} />;
};
继续检查道具而不在道具没有变化时不调用函数,则可以保留它。
如果您只是要向组件提供 initial 值然后在本地进行控制,则可以继续使用React.memo
(因为它仍会呈现对于相同的输入道具来说,是相同的东西),在这种情况下,您不需要React.memo
:
useCallback
只有在const UserInput = React.memo(({ onChange, initialValue }: UserInputProps) => {
const [value, setValue] = useState(initialValue);
const handleChange = (event) => {
setValue(event.target.value);
onChange(event.target.value);
};
return <input type="text" value={value} onChange={handleChange} />;
});
或onChange
发生变化时才会调用。您还可以在那里使用initialValue
,以便再次更改useCallback
属性时,仅更新onChange
上的input
,以避免让React删除旧的处理程序并仅在onChange
发生更改时设置新的
value
旁注:要记住的一件事是,即使您正在使用const UserInput = React.memo(({ onChange, initialValue }: UserInputProps) => {
const [value, setValue] = useState(initialValue);
const handleChange = useCallback(
(event) => {
setValue(event.target.value);
onChange(event.target.value);
},
[onChange]
);
return <input type="text" value={value} onChange={handleChange} />;
});
,每次调用组件函数时也会创建一个新的handleChange
函数。它必须是,因此可以将其作为参数传递到useCallback
中。唯一的区别是您使用该新功能还是第一次创建的原始功能(useCallback
的结果)。我认为重用为给定的一组依赖关系创建的第一个对象的原因是为了最大程度地减少传递给子组件的更改。
答案 1 :(得分:2)
当道具仅包含
onChange
而没有其他元素时,在这种情况下不需要useCallback
,因为整个组件已经基于onChange进行了备忘?
否,可能有必要,memo
和useCallback
的用途不同。
在没有useCallback
的情况下,您可能会对每个渲染器进行“大量计算”:
“大量计算”是指一般情况,而不是仅传递事件值的特定示例。
const UserInput = React.memo(({ onChange = () => {} }) => {
// Uncomment for memoization
// Note that you can implement useCallback with useMemo
// const handleChange = useMemo(() => {
// console.log("heavy computation memoized");
// return event => {
// onChange(event.target.value);
// };
// }, [onChange]);
const handleChange = event => {
// Here we can have some heavy computation
// Not related to this specific usecase
console.log("heavy computation on every render");
onChange(event.target.value);
};
return <input type="text" onChange={handleChange} />;
});
如果我们添加一个额外的prop(例如的初始值),那么我认为
useCallback
会很有用,因为否则handleChange
将被重新创建,即使onChange不变,但值已更改。正确吗?
如果您要使用受控组件(由于使用了value
的{{1}}属性), input
将被初始化一次,因此试图记住它是毫无用处的(出于什么目的?):
initialValue