this example的问题。
我有一个Input
组件。此输入组件具有onChange
道具,可以处理内部中的所有数据更改。
应该如此,如果我从外部更新了value
,则不会触发onChange
道具,因为输入组件内部没有任何变化。如果您开始输入onChange
道具,就会触发,我也可以从外部更新状态。
但是,如果满足某些条件(在我的示例中只是布尔状态),我想从内部预填充输入字段,因此,我必须调用onChange
事件,以便App可以更新从外部状态。
问题/矛盾之处在于,useEffect
检查条件现在需要onChange
道具作为依赖项,并且由于该道具是一种方法,因此它将在每次渲染时更改。这意味着现在,由于再次触发useEffect,因此发生任何更改时,输入元素始终会从useEffect重置为值。
如果允许我从useEffect依赖关系中删除onChange
道具,我的问题就不会出现,但这当然违反了useEffect钩子的规则。
我想到的唯一“解决方案”:
我已经在不同形状的场景中遇到了这个问题,所以我真的希望能得到一个可以普遍应用于类似场景的答案。也许我的代码中只是关于如何使用事件处理程序的反模式?
在此先感谢您提供所有答案^^。
答案 0 :(得分:1)
我会将if语句更改为仅在prefillCondition
更改后才运行。这意味着您需要知道上一次渲染的值。进行内联看起来像:
const [prefillCondition, setPrefillCondition] = React.useState(false);
const previous = useRef();
React.useEffect(() => {
previous.current = prefillCondition;
})
React.useEffect(() => {
// On the first render, previous.current will be undefined. On every render after that
// it will tell you what value prefillCondition had on the previous render.
if (prefillCondition && !previous.current) {
onChange("value from useEeffff");
}
}, [onChange, prefillCondition, previous]);
我发现想记住上一个渲染中的值是很常见的。如果您也这样做,则可能需要考虑将该逻辑提取到自定义钩子中:
const usePrevious = (value) => {
const previous = useRef();
React.useEffect(() => {
previous.current = value;
})
return previous.current;
}
// used like:
const [prefillCondition, setPrefillCondition] = React.useState(false);
const prevPrefillCondition = usePrevious(prefillCondition);
React.useEffect(() => {
if (prefillCondition && !prevPrefillCondition) {
onChange("value from useEeffff");
}
}, [onChange, prefillCondition, prevPrefillCondition]);
答案 1 :(得分:1)
考虑这个
const a = () => 'foo bar'
const b = () => 'foo bar'
a == b // false
即使函数具有相同的代码,但具有不同的内存引用,因此在React中,它始终显示为新的(更改的)prop,这就是为什么调用re-render的原因 而且由于您总是传递新的匿名onChange回调,因此每次都会调用useEffect。
因此您可以从依赖关系数组中忽略它(请注意ESlint规则)
React.useEffect(() => {
// this would supposibly fetch some default value based on conditions and the call an onChange
if (prefillCondition) {
onChange("value from useEeffff");
}
}, [prefillCondition]); // eslint-disable-line react-hooks/exhaustive-deps
或使用React.useCallback()
函数可以完全解决您的问题,并防止在每个渲染器上创建新函数。
const App = () => {
const [myVal, setMyVal] = React.useState("");
const handler = React.useCallback((a) => {
console.log("onchange", a);
setMyVal(a);
}, []);
return (
<div>
<Input value={myVal} onChange={handler} />
<div>
<button
onClick={() => {
setMyVal("smth");
}}
>
set to smth from outside
</button>
</div>
</div>
);
};
答案 2 :(得分:0)
不能在输入中设置默认值
defaultValue={prefillCondition ? "text here" : ""}