cbd*_*per 8 javascript reactjs react-hooks
我有一个<BasicForm>用于构建表单的类组件。它处理验证和所有表格state。它通过React上下文向输入(自渲染起)提供所有必需的功能(onChange,onSubmit等)。childrenBasicForm
它按预期工作。问题在于,现在我将其转换为使用React Hooks,在尝试复制以下是类时的行为时,我感到疑惑:
class BasicForm extends React.Component {
...other code...
touchAllInputsValidateAndSubmit() {
// CREATE DEEP COPY OF THE STATE'S INPUTS OBJECT
let inputs = {};
for (let inputName in this.state.inputs) {
inputs = Object.assign(inputs, {[inputName]:{...this.state.inputs[inputName]}});
}
// TOUCH ALL INPUTS
for (let inputName in inputs) {
inputs[inputName].touched = true;
}
// UPDATE STATE AND CALL VALIDATION
this.setState({
inputs
}, () => this.validateAllFields()); // <---- SECOND CALLBACK ARGUMENT
}
... more code ...
}
Run Code Online (Sandbox Code Playgroud)
当用户单击“提交”按钮时,BasicForm应“触摸”所有输入,然后才调用validateAllFields(),因为仅在触摸输入后才会显示验证错误。因此,如果用户没有触摸任何东西,则BasicForm需要确保在调用validateAllFields()函数之前先“触摸”每个输入。
当我使用类时,我这样做的方法是在setState()函数上使用第二个回调参数,如您在上面的代码中所见。并确保validateAllField()只有在状态更新后(涉及所有字段的状态)才被调用。
但是,当我尝试将第二个回调参数与状态挂钩一起使用时,出现useState()以下错误:
const [inputs, setInputs] = useState({});
... some other code ...
setInputs(auxInputs, () => console.log('Inputs updated!'));
Run Code Online (Sandbox Code Playgroud)
警告:useState()和useReducer()挂钩的状态更新不支持第二个回调参数。要在渲染后执行副作用,请使用useEffect()在组件主体中声明它。
因此,根据上面的错误消息,我正在尝试使用useEffect()挂钩。但这使我有些困惑,因为据我所知,useEffect()它不是基于状态更新,而是基于渲染执行。它在每次渲染后执行。而且我知道React可以在重新渲染之前对一些状态更新进行排队,所以我觉得我无法完全控制useEffect()钩子何时执行,就像我在使用类和setState()第二个回调参数时一样。
到目前为止,我得到的是(似乎正在运行):
function BasicForm(props) {
const [inputs, setInputs] = useState({});
const [submitted, setSubmitted] = useState(false);
... other code ...
function touchAllInputsValidateAndSubmit() {
const shouldSubmit = true;
// CREATE DEEP COPY OF THE STATE'S INPUTS OBJECT
let auxInputs = {};
for (let inputName in inputs) {
auxInputs = Object.assign(auxInputs, {[inputName]:{...inputs[inputName]}});
}
// TOUCH ALL INPUTS
for (let inputName in auxInputs) {
auxInputs[inputName].touched = true;
}
// UPDATE STATE
setInputs(auxInputs);
setSubmitted(true);
}
// EFFECT HOOK TO CALL VALIDATE ALL WHEN SUBMITTED = 'TRUE'
useEffect(() => {
if (submitted) {
validateAllFields();
}
setSubmitted(false);
});
... some more code ...
}
Run Code Online (Sandbox Code Playgroud)
我正在使用useEffect()挂钩来调用该validateAllFields()函数。由于useEffect()在每个渲染器上都执行,validateAllFields()因为我不想在每个渲染器上都需要,所以我需要一种方法来知道何时调用。因此,我创建了submitted状态变量,以便可以知道何时需要该效果。
这是一个好的解决方案吗?您可能想到什么其他解决方案?感觉真的很奇怪。
想象一下该validateAllFields()函数在任何情况下都不能被调用两次。我怎么知道在下一次渲染时我的submitted状态已经100%确定为“假”?
我可以依靠React在下一次渲染之前执行每个排队状态更新吗?这样可以保证吗?
Col*_*rdo 10
我最近遇到了这样的事情(这里有这样的问题),看起来你想出的方法是一个不错的方法。
您可以添加一个 arg 来useEffect()执行您想要的操作:
例如
useEffect(() => { ... }, [submitted])
Run Code Online (Sandbox Code Playgroud)
以观察 中的变化submitted。
另一种方法可能是修改钩子以使用回调,例如:
import React, { useState, useCallback } from 'react';
const useStateful = initial => {
const [value, setValue] = useState(initial);
return {
value,
setValue
};
};
const useSetState = initialValue => {
const { value, setValue } = useStateful(initialValue);
return {
setState: useCallback(v => {
return setValue(oldValue => ({
...oldValue,
...(typeof v === 'function' ? v(oldValue) : v)
}));
}, []),
state: value
};
};
Run Code Online (Sandbox Code Playgroud)
通过这种方式,您可以模拟 'classic' 的行为setState()。
| 归档时间: |
|
| 查看次数: |
4141 次 |
| 最近记录: |