setState第二个参数回调函数在状态挂钩中的替代方法

时间:2020-01-10 07:54:30

标签: reactjs

我为问题创建了一个代码沙箱示例: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>
    );
  }
}

我们将<Counter>组件呈现在<form>中,并且要在更改<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更新会破坏代码。

对looooooooong的帖子表示抱歉,感谢您阅读我的故事。这是我的问题:

  1. 解决方法1和2如何?功能示例是否有“最佳解决方案”?
  2. 我们在做错什么吗?例如,也许我们根本不应该使用隐藏的输入来提交表单?

任何想法都会感激:)

1 个答案:

答案 0 :(得分:0)

您可以在this.handleSubmit()中呼叫componentDidUpdate()吗?

由于您的计数器已绑定到value状态,因此如果状态发生变化,它应该重新呈现。

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

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