在componentDidMount中异步/等待以正确的顺序加载

时间:2019-01-12 01:02:35

标签: javascript reactjs

在以正确的顺序加载多个函数时遇到一些麻烦。从下面的代码中,第一个和第二个功能是获取companyID companyReference,而不是彼此依赖。

第三个功能需要由第一和第二个功能设置的state才能达到获得companyName的目的。

async componentDidMount() {
    const a = await this.companyIdParams();
    const b = await this.getCompanyReference();
    const c = await this.getCompanyName();
    a;
    b;
    c;
  }

  componentWillUnmount() {
    this.isCancelled = true;
  }

  companyIdParams = () => {
    const urlString = location.href;
    const company = urlString
      .split('/')
      .filter(Boolean)
      .pop();
    !this.isCancelled &&
      this.setState({
        companyID: company
      });
  };

  getCompanyReference = () => {
    const { firebase, authUser } = this.props;
    const uid = authUser.uid;
    const getUser = firebase.user(uid);
    getUser.onSnapshot(doc => {
      !this.isCancelled &&
        this.setState({
          companyReference: doc.data().companyReference
        });
    });
  };

  getCompanyName = () => {
    const { firebase } = this.props;
    const { companyID, companyReference } = this.state;
    const cid = companyID;
    if (companyReference.includes(cid)) {
      const getCompany = firebase.company(cid);
      getCompany.onSnapshot(doc => {
        !this.isCancelled &&
          this.setState({
            companyName: doc.data().companyName,
            loading: false
          });
      });
    } else if (cid !== null && !companyReference.includes(cid)) {
      navigate(ROUTES.INDEX);
    }
  };

如何在componentDidMount内部实现此目标?

2 个答案:

答案 0 :(得分:3)

setState是异步的,因此您无法确定以同步方式更新状态的时间。

1) 我建议您不要将componentDidMount与async一起使用,因为该方法属于react生命周期。

相反,您可以这样做:

componentDidMount() {
  this.fetchData();
}

fetchData = async () => {
  const a = await this.companyIdParams();
  const b = await this.getCompanyReference();
  const c = await this.getCompanyName();
}

2)

companyIdParams方法没有返回值,因此您什么都没有等待。 如果需要等待,则setState完成时我将返回一个承诺;

companyIdParams = () => {
  return new Promise(resolve => {
    const urlString = location.href;
    const company = urlString
      .split('/')
      .filter(Boolean)
      .pop();
    !this.isCancelled &&
      this.setState({
        companyID: company
      }, () => { resolve() });
  });
};

与getCompanyReference相同:

getCompanyReference = () => {
  return new Promise(resolve => {
    const { firebase, authUser } = this.props;
    const uid = authUser.uid;
    const getUser = firebase.user(uid);
    getUser.onSnapshot(doc => {
      !this.isCancelled &&
        this.setState({
          companyReference: doc.data().companyReference
        }, () => { resolve() });
    });
  });
};

3)

如果要并行化承诺,可以将以前的代码更改为此:

const [a, b] = await Promise.all([
  await this.companyIdParams(),
  await this.getCompanyReference()
]);

4)

根据您的代码,第三个promise不是promise,因此您可以(再次;)更新以上代码:

const [a, b] = .....
const c = this.getCompanyName()

编辑:要点不是要遵循的步骤

答案 1 :(得分:2)

由于最后一个api调用取决于前两个api调用的响应,因此请使用Promise.all的组合,该组合在解析后将具有进行最后一个从属调用的数据

async componentDidMount() {
    let [a, c] = await Promise.all([
        this.companyIdParams(),
        this.getCompanyReference()
    ]);

    const c = await this.getCompanyName();
}