【问题标题】:How can I wait until the functions finish in Reactjs?我怎样才能等到 Reactjs 中的函数完成?
【发布时间】:2020-12-01 14:59:49
【问题描述】:

嗨,我是 reactjs 的新手,我正在尝试使用 function 构建 button,并通过 Reactjs 进行一些计算。逻辑是,首先我会通过两个函数从database 中得到两个lists。在这 2 个functions 返回结果和setState 之后,计算函数将继续执行其工作。但不知何故,状态没有被更新,它会崩溃。如何确保在计算之前更新状态?非常感谢!

代码:

export default class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      dividendList : [],
      divisorList : [],
};
}
  getDividend(){
    var self = this;
    axios.post(SERVER_NAME + 'api/getDividend', {})
        .then(function(response){
          let results = response.data;
          console.log(results)
          self.setState({ dividendList : results.data})
        })
        .catch(function(err){
          console.log(err)
        });
  } 
  getDivisor(){
    var self = this;
    axios.post(SERVER_NAME + 'api/getDivisor', {})
        .then(function(response){
          let results = response.data;
          console.log(results)
          self.setState({ divisorList : results.data})
        })
        .catch(function(err){
          console.log(err)
        });
  }

  doCal = () => {
    var self = this;
    self.getDividend();
    self.getDivisor();
    const { dividendList , divisorList} = self.state;
    # then will loop the list and do math
    # but since the state is not update, both lists are empty []
}

尝试过的承诺;

   getDivisor(){
    var self = this;
    return new Promise((resolve, reject) => {
      axios.post(SERVER_NAME + 'api/draw/getDivisor', {})
      .then(function(response){
        resolve(response)
      })
      .catch(function(err){
        resolve();
      });
    }) 
  } 

【问题讨论】:

  • 首先return axios.post(... 然后你可以使用async/await(或.then)和Promise.all ...顺便说一句,为什么你的网址像@987654335 @ ...为什么是双重的/
  • 哦错字,你的意思是在doCal函数中返回axios响应数据和setstate?
  • 如果你想等到 axio.post 完成,你需要在那些函数中返回它,然后你可以在 doCal 中使用前面注释中的任何一种方法

标签: javascript reactjs promise


【解决方案1】:

我认为这里的问题是 self.getDividend();self.getDivisor(); 是异步操作。他们将需要一些时间来完成。当您点击下一行 const { dividendList , divisorList} = self.state; 时,这些操作尚未完成,您最终会得到空列表。

解决此问题的一种方法是在 getDividend 和 getDivisor 完成后移动 doCal 函数逻辑。您也可以并行执行这些操作,而不是按顺序执行。我使用异步格式而不是 .then()。它只是一种合成糖。如果您愿意,也可以使用 .then() 实现同样的效果

async function doCalc() {
  const prom1 = axios.get('https://..dividentList');
  const prom2 = axios.get('https://..divisorList');
  const results = await Promise.all([ prom1, prom2]); // wait for both promise to complete
  // look inside results to get your data and set the state
  // continue doCal logic

}

使用 .then()

request1('/dividentList')
.then((res) => {
    //setState for divident
    return request2('/divisorList'); // this will return a promise to chain on
})
.then((res) => {
    setState for divisor
    return Promise.resolve('Success') // we send back a resolved promise to continue chaining
})
.then(() => {
    doCalc logic
})
.catch((err) => {
    console.log('something went wrong');
});

【讨论】:

  • 嗨,是的,我想是的。我试图兑现承诺,但似乎行不通。我是 reactjs 中的异步新手。我如何确保他们返回列表并采取进一步措施?
  • 感谢您的代码,我理解您的逻辑。但似乎不允许在异步函数中调用“this.state”?当我打印状态“Uncaught (in promise) TypeError: Cannot read property 'state' of undefined”时我得到了这个
  • 我更新了使用 .then() 格式的答案。无法将代码剪切到评论中
【解决方案2】:

我查看了您的代码,并认为应该像这样更改它是正确的。

export default class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      dividendList: [],
      divisorList: [],
    };
  }

  componentDidMount() {
    // the API just need be called once, so put here
    this.getDividend()
    this.getDivisor()
  }

  componentDidUpdate(_, prevState) {
    const { dividendList , divisorList } = this.state;
    // Ensure that the answer is only calculated once
    // the answer is only be calculated while the two list data are obtained
    if (
      prevState.divisorList.length === 0 &&
      prevState.dividendList.length === 0 &&
      divisorList.length > 0 &&
      dividendList.length > 0
    ) {
      doCal()
    }
  }

  getDividend(){
    var self = this;
    axios.post(SERVER_NAME + 'api/getDividend', {})
        .then(function(response){
          let results = response.data;
          console.log(results)
          self.setState({ dividendList : results.data})
        })
        .catch(function(err){
          console.log(err)
        });
  } 
  getDivisor(){
    var self = this;
    axios.post(SERVER_NAME + 'api/getDivisor', {})
        .then(function(response){
          let results = response.data;
          console.log(results)
          self.setState({ divisorList : results.data})
        })
        .catch(function(err){
          console.log(err)
        });
  }

  doCal = () => {
    const { dividendList , divisorList } = this.state;
    # then will loop the list and do math
    # but since the state is not update, both lists are empty []

    this.setState({ answer: 'xxx' })
  }

  render() {
    const { dividendList, divisorList, answer } = this.state

    if (dividendList.length === 0 && divisorList.length === 0) {
      return <div>Loading...</div>
    }

    if (!answer) {
      return <div>Error</div>
    }

    return <div>{answer}</div>
  }
}

以下只是一些使代码更易于阅读的建议,

  1. 你可以使用箭头功能,这样你就不需要写self.setState({...})
getDividend = () => {
  axios.post(SERVER_NAME + 'api/getDivisor', {})
    .then((response) => {
      let results = response.data;
      console.log(results)
      this.setState({ divisorList : results.data})
    })
    .catch((err) => {
      console.log(err)
    });
}
  1. 你也可以使用 async/await 代替 promise.then
getDividend = async () => {
  const response = await axios.post(SERVER_NAME + 'api/getDivisor', {})  
  let results = response.data;
  console.log(results)
  this.setState({ divisorList : results.data})
}

【讨论】:

    【解决方案3】:

    默认设置'dividendList'和'divisorList'等于'null'。然后,当调用使用这些列表的函数时,创建一个 if 语句来验证这些状态是否为 false(如果它们仍然为 null),然后在函数内部返回,如果不是,它不应该崩溃任何东西。

    【讨论】:

    • 谢谢你的回答,不过我觉得这种做法只能防止程序崩溃而不能立即更新状态?
    • 是的,它可以防止应用程序在列表准备好之前崩溃,之后你就可以开始了。如果您正在发出异步请求,则不能期望立即访问它
    猜你喜欢
    • 2011-12-14
    • 2016-05-19
    • 2014-09-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多