访问 this.state 后如何确保 setState 调用已经执行?

Posted

技术标签:

【中文标题】访问 this.state 后如何确保 setState 调用已经执行?【英文标题】:How to make sure the setState calls are already executed after accessing this.state? 【发布时间】:2021-04-06 11:04:49 【问题描述】:

我有一个注册表。当我单击 Register 按钮时,所有TextInputs 都已验证,并且对于每个字段,我都会调用一个函数,我在其中调用例如this.setState(usernameError: 'This field is required')。 因此,对于每个文本字段,我都有一个函数来设置该字段的错误状态。在我按下 Register 按钮后,我想验证所有字段,然后如果状态中有任何字段错误,则返回该函数(如果所有字段都没有正确填写,用户可能无法注册)。问题是:因为setState是异步的,所以不保证我检查的时候所有的字段错误都已经正确设置了。

2 个重要注释:

    我知道 setState 的第二个参数(回调),但我无法执行此回调中的条件(检查状态中的字段错误),因为 setState 调用位于它们自己的函数中 它们位于自己的函数中,因为我想重用逻辑(我也在其他地方调用validate<FieldName>函数,例如当onChangeText事件发生时)

所以我的问题是:如何确保在检查其值时已更新状态而不放弃我可重用的“验证器函数”?

一些代码使其更清晰:

state =  usernameError: '', firstNameError: '', lastNameError: '' ;

setUsernameError = () =>  // This function is also called elsewhere than in handlePressRegister
    const  username  = this.state;
    if (username === '')
        this.setState( usernameError: 'Required field' );
    else if (username.length < 2)
        this.setState( usernameError: 'Minimum 2 characters' );
    else
        this.setState( usernameError: undefined );


setFirstNameError = () =>  // This function is also called elsewhere than in handlePressRegister
    ...shortened for brevity...


setLastNameError = () =>  // This function is also called elsewhere than in handlePressRegister
    ...shortened for brevity...


handlePressRegister = () => 
    const  usernameError, firstNameError, lastNameError  = this.state;

    this.setUsernameError();
    this.setFirstNameError();
    this.setLastNameError();

    if (usernameError || firstNameError || lastNameError) // The errors may not be set in the state yet
        return;

希望你能正确理解我的问题。

【问题讨论】:

您是否将组件的 state 传递给一个不是 React 组件的函数以重用该函数? 【参考方案1】:

我会通过让各种set[X]Error 函数返回它们的新值来处理这个问题。例如:

setUsernameError = () =>  
    const  username  = this.state;
    let error = undefined;
    if (username === '')
      error = 'Required field';
    else if (username.length < 2)
      error = 'Minimum 2 characters';

    this.setState( usernameError: error );

    return error;


handlePressRegister = () => 
  const usernameError = this.setUsernameError();
  const firstNameError = this.setFirstNameError();
  const lastNameError = this.setLastNameError();

  if (usernameError || firstNameError || lastNameError) 
    return;
  
  // ...

【讨论】:

【参考方案2】:

如果您promisifysetState,您可以从每个验证器调用中返回它并在其上调用Promise.all

setUsernameError = () =>  // This function is also called elsewhere than in handlePressRegister
    const  username  = this.state;
    if (username === '')
        return setStatePromisified( usernameError: 'Required field' );
    // ...
Promise.all([
    this.setUsernameError(),
    this.setFirstNameError(),
    this.setLastNameError(),
])
    .then(() => 
        // state will be updated now
        const  usernameError, firstNameError, lastNameError  = this.state;
        if (usernameError || firstNameError || lastNameError) 
            return;
        
        // submit?
    );

另一种选择是将另一个属性添加到状态中,例如validating,当按下注册按钮时会设置该属性。下一次渲染,在componentDidUpdate 中检测其变化,重置validating,并根据需要继续执行逻辑(如果没有错误则提交表单?)。

【讨论】:

以上是关于访问 this.state 后如何确保 setState 调用已经执行?的主要内容,如果未能解决你的问题,请参考以下文章

如何在`this.state`对象中获取状态值

为啥我们需要在 ReactJS 中使用 bind() 来访问 this.props 或 this.state? [复制]

反应 this.state 未定义的数组

当第二次访问屏幕时,React Native null不是对象(评估'_this2.state.data')错误

如何在 React JS 中的 css 转换结束后使用 setState?

如何将 this.state 转移到 react-routes?