【问题标题】:Child Stateless Functional Component doesn't update even after parent State updates即使在父状态更新后,子无状态功能组件也不会更新
【发布时间】:2018-08-26 20:41:59
【问题描述】:

我的父组件在其状态中有一个名为formIsValid 的属性,最初设置为false。我的表单也有一个提交按钮。我希望在某些输入字段(名字和姓氏输入)中有数据之前禁用提交按钮。

这是我的状态:

  state = {
    employees: [],
    costEstimates: emptyCosts(),
    relationshipOptions: [],
    newEmployee: emptyEmployee(),
    formIsValid: false
  };

这个函数处理名字和姓氏输入的变化:

  // handle input into "First Name" and "Last Name" inputs
  handleChangeValue = async e => {
    const newEmployee = { ...this.state.newEmployee };
    newEmployee[e.currentTarget.name] = e.currentTarget.value;

    this.setState({ newEmployee });

    this.validateIfCanBeSubmitted();

    await this.updateCostsData(newEmployee); // this is an api thing, not relevent
  };

这是在状态中设置formIsValid 属性的原因。此属性作为道具发送到提交按钮。

  validateIfCanBeSubmitted = () => {
    const { firstName, lastName } = this.state.newEmployee;

    let formIsValid = firstName && lastName ? true : false;

    this.setState({ formIsValid });
  };

如果该州的员工属性的名字和姓氏为空,则该提交按钮正确地被禁用。问题是它“被 1 次更新关闭”。就好像道具没有被传播到子按钮组件,直到下一次状态改变之后。这是问题的 GIF:

这是子组件的样子。它只是一个普通的 HTML 按钮,但它位于无状态功能组件中,因此问题不在于组件的状态:

    <button
      type="button"
      onClick={onSubmit}
      className={'btn btn-primary mr-1 ' + (formIsValid ? '' : 'disabled')}
      disabled={!formIsValid}
    >

【问题讨论】:

    标签: javascript reactjs


    【解决方案1】:

    setState() 是异步的!
    this.validateIfCanBeSubmitted(); 在旧状态上执行;执行您的函数时,此更新 this.setState({ newEmployee }); 尚未传播到 this.state

    validateIfCanBeSubmitted 设为更新函数。

    validateIfCanBeSubmitted = ({ newEmployee: { firstName, lastName }}) => {
      return {
        formIsValid: firstName && lastName ? true : false
      };
    }
    

    并相应地使用它:

    handleChangeValue = async e => {
      const {name, value} = e.currentTarget;
      const newEmployee = { 
        ...this.state.newEmployee, 
        [name]: value
      };
    
      this.setState({ newEmployee });
      this.setState(this.validateIfCanBeSubmitted);
    
      // this is an api thing, not relevant
      await this.updateCostsData(newEmployee); 
    };
    

    实际上,handleChangeValue 中的代码也应该在这样的函数中,因为它使用以前的状态来计算新的状态。

    那么如何组合它们:

    handleChangeValue = e => {
      const {name, value} = e.currentTarget;
      this.setState((state) => {
        const newEmployee = { 
          ...this.state.newEmployee, 
          [name]: value
        };
        const { firstName, lastName } = newEmployee;
        const formIsValid = firstName && lastName ? true : false;
    
        //and since you never use the returned Promise, why make anything async?
        this.updateCostsData(newEmployee);
    
        return { newEmployee, formIsValid  };
      });
    };
    

    【讨论】:

    • 我不知道 setState 是异步的。这解释了很多,谢谢。我有一个问题:我尝试做await this.setState({ newEmployee }),这实际上似乎解决了我的问题。有什么理由我不应该等待 setState() 吗?
    • @Andrio 请再检查一次。我知道 setState 将回调函数作为第二个参数,我从未听说它返回一个 Promise。在文档中我也没有看到记录,并且在快速测试中setState() 返回了undefined。所以请检查这是否是一些未记录的行为,您是否真的得到了 Promise(以便您可以使用 await),或者这是否只是巧合。
    • await 放在它前面绝对解决了我的问题;我什么也没做。
    • @Andrio 只知道,如果setState 没有返回 Promise,那么这个“修复”只是巧合,在执行此任务时计算机负载足够时可能会失败;或任何 React 更新。
    猜你喜欢
    • 2021-07-26
    • 2021-01-12
    • 2019-11-24
    • 2018-02-20
    • 1970-01-01
    • 2023-03-29
    • 2021-09-29
    • 1970-01-01
    • 2018-11-03
    相关资源
    最近更新 更多