异步/等待与同步功能更改反应状态

时间:2020-03-10 12:42:17

标签: javascript reactjs typescript

我在load() / async函数和React中更改状态时遇到问题。 这是我的异步功能,该功能是通过单击按钮触发的:

await

在此函数中,我使用async startNewEntry() { this.addIssue(); let issue_id; console.log(this.state.timeEntry, "started_timeEntry") if (this.state.timeEntry?.issue?.id) { issue_id = this.state.timeEntry?.issue?.id; } else { issue_id = (await this.issueService.list()).data[0]?.id; } const { data } = await this.timeEntryService.create({ comments: this.state.timeEntry.comments, issue_id, spent_on: moment(new Date()).format("YYYY-MM-DD"), hours: 0.01, activity_id: this.localStorageService.get("defaultActivityId") }); ,并使用this.addIssue,这会更改类的组件状态:

this.createIssue

如您所见,在我的异步函数中,我第一次拥有新的状态,但实际上异步函数在我的addIssue() { this.projectService.list([]).then(response => { response.data = response.data.filter((x: any) => x.status === 1); this.setState( { activeProjects: response.data }, () => { this.createIssue(); } ); }); } createIssue() { this.issueAddService .create({ project_id: this.state.activeProjects[0].id, tracker_id: trakerId, priority_id: priorityId, subject: this.state.timeEntry.comments, description: this.state.timeEntry.comments }) .then(response => { let timeEntry = this.state.timeEntry; timeEntry.issue = response.data; this.setState({ timeEntry }); }) .catch(error => { console.log("error", error); }); } 函数之前起作用。我知道这个问题可能有点古怪,但是谢谢前进!

2 个答案:

答案 0 :(得分:2)

如果您希望startNewEntry等到addIssue完成工作之后,您需要:

  1. addIssue返回完成工作后的承诺,并且
  2. 调用时使用awaitawait this.addIssue();

如果您需要startNewEntry来查看更新后的状态,则需要从状态完成处理程序回调中履行addIssue的承诺,如下所示:

addIssue() {
  // *** Return the promise chain to the caller
  return this.projectService.list([]).then(response => {
    response.data = response.data.filter((x: any) => x.status === 1);
    // *** Create a new promise
    return new Promise(resolve => {
      this.setState(
        {
          activeProjects: response.data
        },
        () => {
          this.createIssue();
          resolve(); // *** Fulfill the promise
        }
      );
    });
  });
}

new Promise通常是一种反模式,尤其是当您有另一个可以从中进行承诺的承诺时。但是在这种情况下,由于您需要等待来自setState的回调(未启用Promise),因此是合适的。 (


请注意my comment。我认为您正在建立一个无限循环...

答案 1 :(得分:1)

我不是React专家,但是我不完全理解为什么在这个地方有很多setState调用。

如果将setState留在函数的末尾,则可能不必担心对异步调用的正确排序(尽管其他答案确实显示了如何实现)。

也许一次调用它可能会使代码更清晰。我欢迎更正...

async startNewEntry() {                
    const activeProjects = await fetchActiveProjects()
    const issue = await this.createIssue()         
    const timeEntry = await createTimeEntry({ issue, comments: this.state.timeEntry.comments })
    this.setState({ activeProjects, issue, timeEntry })
}

async fetchActiveProjects() {
    const { data } = await this.projectService.list([])            
    return data.filter(({ status }) => status === 1)
}

async createIssue() {
    const { data } = await this.issueAddService.create({
        project_id: this.state.activeProjects[0].id,
        tracker_id: trakerId,
        priority_id: priorityId,
        subject: this.state.timeEntry.comments,
        description: this.state.timeEntry.comments
    })  
    return data        
}

async createTimeEntry({issue, comments}) {        
    const { data } = await this.timeEntryService.create({
         comments,
         issue_id: issue?.id || (await this.issueService.list()).data[0]?.id,
         spent_on: moment(new Date()).format("YYYY-MM-DD"),
         hours: 0.01,
         activity_id: this.localStorageService.get("defaultActivityId")
    })  
    return data
}

您可以通过并行化前两个异步调用来进一步加快速度:

async startNewEntry() {                
    const [activeProjects, issue] = 
        await Promise.all([fetchActiveProjects(), this.createIssue()])       
    const timeEntry = await createTimeEntry({ issue, comments: this.state.timeEntry.comments })
    this.setState({ activeProjects, issue, timeEntry })
}