javascript - Reactjs - 排序 if else 和外部 block

标签 javascript reactjs asynchronous

我有一个具有以下功能的 react 组件:

alreadyUpvoted() {
    return this.state.upvotes.indexOf(this.props.context.userId) !== -1
}

alreadyDownvoted() {
    return this.state.downvotes.indexOf(this.props.context.userId) !== -1
}

addUpvote() {
    this.setState(prev => ({
        upvotes: prev.upvotes.concat(this.props.context.userId),
        upvoted: true,
        votes: prev.votes + 1,
    }), () => {
        console.log('add upvote', this.state)
    })
}

removeUpvote() {
    var new_upvotes = this.state.upvotes.concat()
    new_upvotes.pop(this.props.context.userId)
    this.setState(prev => ({
        upvotes: new_upvotes,
        upvoted: false,
        votes: prev.votes - 1,
    }), () => {
        console.log('remove upvote', this.state)
    })
}

addDownvote() {
    this.setState(prev => ({
        downvotes: prev.downvotes.concat(this.props.context.userId),
        downvoted: true,
        votes: prev.votes - 1,
    }), () => {
        console.log('add dowvote', this.state)  
    })
}

removeDownvote() {
    var new_downvotes = this.state.downvotes.concat()
    new_downvotes.pop(this.props.context.userId)
    this.setState(prev => ({
        downvotes: new_downvotes,
        downvoted: false,
        votes: prev.votes + 1,
    }), () => {
        console.log('remove downvote', this.state)
    })
}

postVotesData() {
    var json = {
        upvotes: this.state.upvotes,
        downvotes: this.state.downvotes
    }
    json = JSON.stringify(json)
    console.log(json)
    const url = `/api/reddit/r/${this.props.subreddit}/posts/${this.props.postid}/`
    fetch(url, {
        method: 'PUT',
        headers: {
            'Accept': 'application/json',
            'Content-Type': 'application/json'
        },
        body: json
    })
    .then(response => {
        console.log('response status:', response)
        return response.json()
    })
    .then(res => console.log('response data:', res))
}

我创建了一个 toggleUpvote 函数,它利用了上述所有函数:

toggleUpvote() {
    if (this.alreadyDownvoted()) {
        this.removeDownvote()
        this.addUpvote()
    }
    else if (this.alreadyUpvoted()) {
        this.removeUpvote()
    }
    else {
        this.addUpvote()
    }
    this.postVotesData()
}

这里的问题是 this.postVotesData()if-else block 完成之前执行。

对于当前状态,控件应该转到 else block 。但是,this.postVotesData() 中的 console.logaddUpvote 中的 console.log 之前执行!!

证据: enter image description here

在当前状态下,upvotes 数组在执行 else 后应该有一个值,并且该数组应该在 PUT 中使用。但是,空数组被PUT,然后值被添加到数组中。

我还希望 if block 内的函数按顺序执行。我该如何解决这个问题?

最佳答案

这就是异步 JavaScript 的工作原理。我相信您正在执行异步操作,例如 fetch 调用或 React 的 setState()。 js 中的它们(以及许多其他东西)都是异步的。 为了解决这个问题,您需要使用回调或 promise 。使用 Promise 时,您可以使用 async-await 语法来获得干净的代码。

async toggleUpvote() {
    if (this.alreadyDownvoted()) {
        await this.removeDownvote()
        await this.addUpvote()
    }
    else if (this.alreadyUpvoted()) {
        await this.removeUpvote()
    }
    else {
        await this.addUpvote()
    }
    await this.postVotesData()
}

为此,removeUpvote、addUpvote 和 postVotesData 需要返回 Promise。

如果在这些函数中调用setState,则需要提供setState的回调。或者您可以使用功能集状态模式。

避免此问题的一个简单修复方法是从类似于以下内容的函数返回一个 promise ,并使用上面建议的 async-await 语法。

addUpvote() {
  return new Promise((resolve, reject) => {
    this.setState(prev => ({
        upvotes: prev.upvotes.concat(this.props.context.userId),
        upvoted: true,
        votes: prev.votes + 1,
    }), () => {
        console.log('add upvote', this.state)
        return resolve(); // Signal that the operation has finished
    })
  })
}

关于javascript - Reactjs - 排序 if else 和外部 block ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51464979/

相关文章:

javascript - Angular PWA - 为什么浏览器缓存不断增长?如何阻止它?

javascript - Vite.js 不在多页应用程序中发出 HTML 文件

reactjs - React 函数仅在重新访问页面后运行一次

python - 如何获得非阻塞套接字连接()?

javascript - 网络抓取和 promise

javascript - 在这里正确使用函数式编程 : how do I use . map() 有效吗?

javascript - 即使值与我设置的值不匹配,仍在执行 IF 语句

reactjs - RegEx 可以与 React 测试库一起使用来检查类名吗?

asynchronous - Slack API方法发送 "typing"

javascript - 通过 XMLHttpRequest 获取 img 后加载外部图像作为 div 的背景