TL / DR:
如何正确同步两个挂钩之间的状态?
实施细节:
我将简化示例并使用
useState
,而不是为了简化问题而实际使用的第一个自定义钩子。基本上,被忽略的钩子所做的是它返回一个
state
和辅助函数。所以只画图片:const [email, onEmailChange, onEmailBlur] = useField('init', isEmailValid)
仅用替换了相关问题(尽管此处在技术上是多余的)
const [email, setEmail] = useState('hi')
我将本节摘录留在这里的原因是,这样我就不会得到最初的
useState
多余的评论/答案
有效的方法:
将状态引用传递给只返回它的基本函数。
const useForm = (...fields) => {
return {
fields,
}
}
const form = useForm(email) // updates correctly
问题开始的地方:
现在显然,这件事甚至不需要钩子。当我尝试添加更复杂的逻辑时出现问题
const useForm = (submitFunction, ...fields) => {
const initialForm = {
fields,
wasSubmitted: false,
}
const [form, setForm] = useState(initialForm)
const handleSubmit = (event) => {
event.preventDefault()
if (!fields.some(({ error }) => !!error) {
submitFunction()
}
setForm({
fields,
wasSubmitted: true,
})
}
return [form, handleSubmit] // now the state no longer updates
}
现在我确实怀疑为什么会这样。仅仅因为
useState
初始化了状态的新实例,所以我们只是从传递的状态返回初始值。
问题是,关于如何同步这些内容,我无法真正解决。
具有工作钩和非工作钩的可编辑示例:
答案 0 :(得分:1)
正如您提到的,这是因为useState
中的useForm
设置了form
状态的初始值,并且其值在下一个渲染中不会改变。
如果要保持form
和fields
同步,则每次useEffect
中的值时,都可以使用form
更新fields
的值。变化。
...
const [form, setForm] = useState<Form>(initialForm);
useEffect(() => {
setForm(formState => ({ ...formState, fields }))
}, fields);
...
此解决方案的问题在于,setForm
中的useEffect
每次更改fields
中的值都会引起另一次重新渲染。
解决此问题的另一种方法是不在状态中保存fields
的值,而仅将wasSubmitted
保持在useForm
的状态。
const useForm = (submitFunction, ...fields) => {
const [wasSubmitted, setWasSubmitted] = useState(false);
const handleSubmit = (event) => {
if (fields.some(field => field === "run")) {
submitFunction();
}
setWasSubmitted(true);
};
return [{ fields, wasSubmitted }, handleSubmit];
};