【问题标题】:What is the better way to update other state variable which is dependent on another state variable while re-rendering?在重新渲染时更新依赖于另一个状态变量的其他状态变量的更好方法是什么?
【发布时间】:2019-05-16 16:31:50
【问题描述】:

场景是,在安装组件后,在事件监听器中,我正在设置一个状态变量,而其他状态变量正在通过从后端进行休息调用来设置。

到目前为止,我正在使用 componentWillUpdate 并进行休息调用并设置所有必需的状态。

我尝试使用 componentWillUpdate 方法来计算和设置其他状态变量。但是它多次重新渲染。我想我肯定在这里做错了。

export default class Person extends React.Component {
  constructor(props, context) {
    super(props, context);
    this.state = {
      name: this.props.name,
      age: "",
      country: ""
    };
  }

  componentDidMount() {
    this.setDerivedStates();
  }

  componentWillUpdate() {
    this.setDerivedStates();
  }

  attachListner() {
    document.addEventListner("customEvent", () => {
      this.setState({ name: something });
    });
  }

  setDerivedStates() {
    FetchService.get("url1" + this.state.name).then(response =>
      this.setState({ age: response.age})
    );
    FetchService.get("url2" + this.state.name).then(response =>
      this.setState({ country: response.country })
    );
  }

  render() {
    return (
      <div>
         <p>{this.state.name}</p>
         <p>{this.state.age}</p>
         <p>{this.state.country}</p>
      </div>
    );
  }
}

我想用所有新的状态变量重新渲染组件一次。 请建议我该怎么做。我应该使用哪种生命周期方法以及如何设置所有这些状态?

【问题讨论】:

  • 应该在每次状态更新时重新渲染。为什么这是个问题?如果你想减少setStates 的数量,你可以在setDerivedStates() 中使用Promise.all,这会简化一点,但总的来说,这应该不是问题,因为 React 正在按预期工作。
  • 你忘记了setDerivedStates();中的this.
  • @larz 它再次重新渲染,我想减少它。在我读到的某个地方,我们不应该在 componentWillUpdate 方法中执行 setState。所以我有点怀疑我使用了错误的生命周期方法。但不确定我还应该使用什么。
  • @Vencovsky 感谢伙伴更新了它。

标签: reactjs setstate


【解决方案1】:

您可以使用Promise.all 批处理这两个提取,因此您只需调用一次this.setState -

const [resp1, resp2] = await Promise.all([
        FetchService.get("url1" + this.state.name);
        FetchService.get("url2" + this.state.name);
      ]);

this.setState({ age: resp1.age, country: resp2.country });

另外,componentWillUpdate 被视为unsafe,将来会被弃用。我建议改用componentDidUpdate -

componentDidUpdate = (prevProps, prevState) => {
    if (prevState.name !== this.state.name) {
        this.setDerviedStates();
    }
}

【讨论】:

  • 感谢您的回复。抱歉打错了。两者都是不同的网址。我已经更新了。
  • componentDidMount 在组件挂载后调用一次。我需要在一个状态更改并且组件已经安装后进行休息调用,因此那时不会调用 componentDidMount。
【解决方案2】:

您可以将两个提取都包装在Promise.all 中,这将等待两个Promises 解析,如果一个失败,您将无法访问任何成功解析的Promise/s,并且操作将抛出error

添加componentDidUpdate检查名称状态是否改变,如果改变则重新获取。

componentDidUpdate(prevProps, prevState) {
  if (prevState.name !== this.state.name) {
    this.setDerivedStates();
  } 
}

async setDerivedStates() {
  const url = `url${this.state.name}`;

  try {
    const [age, country] = await Promise.all([
      FetchService.getAge(url),
      FetchService.getCountry(url),
    ]);

    this.setState({ age, country });
  } catch (e) {
    console.log('something went wrong', e);
  }
}

【讨论】:

  • 谢谢阿萨夫。我会试一试。一个小问题,这个componentWillUpdate()如果我在里面setState会不会再被调用?
  • 正如 larz 所说,应该避免使用componentWillUpdate。您可以使用componentDidUpdate 来处理组件更新。问题是,你想什么时候重新获取年龄和国家?你的eventListener 是否在监听输入变化?您是否在每次按键时都重新获取?也包括听众
  • 事件在按钮点击时触发。在那个事件监听器中,如代码 sn-p 所示,我正在设置一个状态,而对于其他状态变量,我想进行休息调用以更新它。
  • 好的,那么当前的解决方案应该可以解决它。请注意,当您从 eventListener 更改状态时,这是一次重新渲染,然后在我们获取并设置状态后,将发生另一次重新渲染
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-30
  • 2019-11-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-26
相关资源
最近更新 更多