setState 第二个参数回调函数在状态钩子中替代



我为我的问题做了一个代码沙箱示例:https://codesandbox.io/s/react-form-submit-problem-qn0de。请尝试单击函数示例和类示例上的"+"/"-"按钮,您将看到差异。在函数示例中,我们总是在提交时获取以前的值。

我将在下面解释有关此示例的详细信息。

我们有这样的反应组件

function Counter(props) {
return (
<>
<button type="button" onClick={() => props.onChange(props.value - 1)}>
-
</button>
{props.value}
<button type="button" onClick={() => props.onChange(props.value + 1)}>
+
</button>
<input type="hidden" name={props.name} value={props.value} />
</>
);
}

它包含两个按钮和一个数值。用户可以按"+"和"-"按钮更改号码。它还渲染了一个输入元素,以便我们可以在<form>.

这就是我们使用它的方式

class ClassExample extends React.Component {
constructor(props) {
super(props);
this.state = {
value: 1,
lastSubmittedQueryString: ""
};
this.formEl = React.createRef();
}
handleSumit = () => {
if (this.formEl.current) {
const formData = new FormData(this.formEl.current);
const search = new URLSearchParams(formData);
const queryString = search.toString();
this.setState({
lastSubmittedQueryString: queryString
});
}
};
render() {
return (
<div className="App">
<h1>Class Example</h1>
<form
onSubmit={event => {
event.preventDefault();
this.handleSumit();
}}
ref={ref => {
this.formEl.current = ref;
}}
>
<Counter
name="test"
value={this.state.value}
onChange={newValue => {
this.setState({ value: newValue }, () => {
this.handleSumit();
});
}}
/>
<button type="submit">submit</button>
<br />
lastSubmittedQueryString: {this.state.lastSubmittedQueryString}
</form>
</div>
);
}
}

我们在<form>中渲染我们的<Counter>组件,并希望在更改<Counter>的值后立即提交此表单。但是,在onChange事件上,如果我们只是这样做

onChange={newValue => {
this.setState({ value: newValue });
this.handleSubmit();
}}

那么我们不会得到更新的值,可能是因为 React 没有同步运行 setState。因此,我们将this.handleSubmit()放在 setState 的第二个参数回调中,以确保它在状态更新后执行。

但是在函数示例中,据我所知,在状态钩子中,没有什么比 setState 的第二个参数回调函数更像了。因此,我们无法实现相同的目标。我们发现了两种解决方法,但我们对其中任何一个都不满意。

解决方法 1

我们尝试使用效果钩子来侦听值何时更改,我们提交表单。

React.useEffect(() => {
handleSubmit();
}, [value])

但是有时我们只需要更改值而不提交表单,我们只想在通过单击按钮更改值时才调用提交事件,因此我们认为应该将其放在按钮的 onChange 事件中。

解决方法 2

onChange={newValue => {
setValue(newValue);
setTimeout(() => {
handleSubmit();
})
}}

这工作正常。我们总是可以得到更新的值。但问题是我们不明白它是如何工作的以及为什么工作,我们从未见过人们以这种方式编写代码。我们担心代码是否会被未来的 React 更新破坏。

对不起,这个帖子很抱歉,谢谢你阅读我的故事。以下是我的问题:

  1. 解决方法 1 和 2 怎么样?函数示例是否有任何"最佳解决方案"?
  2. 我们做错了什么吗?例如,也许我们根本不应该使用隐藏的输入来提交表单?

任何想法将不胜感激:)

你能用componentDidUpdate()来称呼this.handleSubmit()吗?

由于计数器绑定到value状态,因此如果状态发生更改,它应重新呈现。

componentDidUpdate(prevProps, prevState) {
if (this.state.value !== prevState.value) {
this.handleSubmit();
}
}

这可确保仅在value状态更改时触发提交(在 setState 完成后(

已经有一段时间了。在阅读了 React 18 的更新细节后,我意识到差异是由 React 自动批处理函数组件中的状态更新引起的,而摆脱它的"官方"方法是使用 ReactDOM.flushSync((。

import { flushSync } from "react-dom";
onChange={newValue => {
flushSync(() => {
setValue(newValue)
});
flushSync(() => {
handleSubmit();
});
}}

相关内容

最新更新