本文介绍了如何在 React (async/await) 中创建原子进程?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

想象一个按下按钮就可以点赞的帖子.此按钮修改远程数据库,因此将点赞关联到特定帖子需要一些时间.

现在,如果用户使用此代码开始如此快速地按下按钮:

 状态 = {是喜欢:假,}handlePress = () =>{这个.setState({isLiked: !this.state.isLiked,},this.handleLike);};handleLike = async() =>{const { postId } = this.props;尝试 {控制台日志(isLiked?喜欢":不喜欢")等待 db.processLike(postId);} 抓住(错误){//如果发生错误,则反转 'isLiked' 状态this.setState({isLiked: !this.state.isLiked,});//TODO - 在祝酒词中向用户警告错误控制台日志(错误);}控制台日志(完成");};

由于一切都是异步的,所以可以看到这种情况:

喜欢

不喜欢

完成 <---------不喜欢完成

完成

我想创建一个状态isLiking";避免在所有异步作业完成之前运行代码.像这样:

 状态 = {isLiking:假,是喜欢:假,}handlePress = () =>{如果(this.state.isLiking)返回;<------------------------------------这个.setState({isLiking: 真, <------------------------------------isLiked: !this.state.isLiked,},this.handleLike);};handleLike = async() =>{const { postId } = this.props;尝试 {控制台日志(isLiked?喜欢":不喜欢");等待 db.processLike(postId);} 抓住(错误){//如果发生错误,则反转 'isLiked' 状态this.setState({isLiked: !this.state.isLiked,});//TODO - 在祝酒词中向用户警告错误控制台日志(错误);}this.setState({ isLiking: false });<------------------------------------控制台日志(完成");};

这样一切都会好起来的,但是如果用户快速按下按钮,他将无法看到 GUI 的变化(喜欢按钮的颜色(喜欢的按钮颜色(红色,喜欢,白色)),直到所有过程描述完毕在上面的代码中完成.

我也想过像这样制作一个去抖动函数(用于handlePress):

export const debounce = (func, wait,immediate) =>{/*返回一个函数,只要它继续被调用,就不会被触发.该函数将在停止调用后被调用N 毫秒.如果传递了 `immediate`,则触发该函数前缘,而不是后缘.*/让超时;返回函数(){让上下文 = 这个,args = 参数;让以后 = 函数 () {超时=空;if (!immediate) func.apply(context, args);};let callNow = 立即 &&!超时;清除超时(超时);timeout = setTimeout(稍后,等待);if (callNow) func.apply(context, args);};};...debuncedHandlePress = debounce(this.handlePress, 500);//现在,当按钮被按下时,它会调用这个函数,而不是原来的handlePress

但是有了这个,我唯一要做的就是减少获得混乱结果的机会.也就是说,我还是和第一个代码有同样的问题.

有什么想法可以按照我想要的方式做我想做的事情,这样我得到的结果是有序的并避免等待写入数据库的时间?

谢谢.

解决方案

解决方案是立即禁用按钮.使用 setState,你不能指望 isLinking 立即更新,这就是你生气的原因.解决方案之一是使用 flag variable 而不是使用 state.

您可以通过这种方式修复.

 状态 = {是喜欢:假,}构造函数(道具){this.isLiking = false;<------------------------------------}handlePress = () =>{this.isLiking = true;<------------------------------------这个.setState({isLiked: !this.state.isLiked,},this.handleLike);};handleLike = async() =>{const { postId } = this.props;尝试 {控制台日志(isLiked?喜欢":不喜欢");等待 db.processLike(postId);} 抓住(错误){//如果发生错误,则反转 'isLiked' 状态this.setState({isLiked: !this.state.isLiked,});//TODO - 在祝酒词中向用户警告错误控制台日志(错误);}this.isLiking = false;<------------------------------------控制台日志(完成");};

Imagine a post that can be liked when pressing a button. This button modifies a remote database, so it will take a little while to associate the like to the specific post.

Now, if an user starts pressing the button so fast with this code:

 state = {
    isLiked: false,
 }

 handlePress = () => {
    this.setState(
      {
        isLiked: !this.state.isLiked,
      },
      this.handleLike
    );
  };

  handleLike = async () => {
    const { postId } = this.props;

    try {
      console.log(isLiked ? "Liking" : "Disliking")
      await db.processLike(postId);
    } catch (err) {
      // If an error has occurred, reverse the 'isLiked' state
      this.setState({
        isLiked: !this.state.isLiked,
      });

      // TODO - Alert the error to the user in a toast
      console.log(err);
    }

    console.log("DONE");
  };

As all is async, it is possible to see this situation:

I have thought to create a state "isLiking" to avoid running the code until all the async job has finished. Something like this:

 state = {
    isLiking: false,
    isLiked: false,
 }

 handlePress = () => {

    if (this.state.isLiking) return; <------------------------------------

    this.setState(
      {
        isLiking: true, <------------------------------------
        isLiked: !this.state.isLiked,
      },
      this.handleLike
    );
  };

  handleLike = async () => {
    const { postId } = this.props;

    try {
      console.log(isLiked ? "Liking" : "Disliking"); 
      await db.processLike(postId);
    } catch (err) {
      // If an error has occurred, reverse the 'isLiked' state
      this.setState({
        isLiked: !this.state.isLiked,
      });

      // TODO - Alert the error to the user in a toast
      console.log(err);
    }

    this.setState({ isLiking: false }); <------------------------------------

    console.log("DONE");
  };

With this all is going OK, but if the user press the button fast, he will not be able to see the GUI changes (the like button color (red if is liked, white if not)) until all the process described in the code above finishes.

I have also thought to make a debounced function (for the handlePress) like this:

export const debounce = (func, wait, immediate) => {
  /*
    Returns a function, that, as long as it continues to be invoked, will not
    be triggered. The function will be called after it stops being called for
    N milliseconds. If `immediate` is passed, trigger the function on the
    leading edge, instead of the trailing.
  */

  let timeout;
  return function () {
    let context = this,
      args = arguments;

    let later = function () {
      timeout = null;
      if (!immediate) func.apply(context, args);
    };

    let callNow = immediate && !timeout;

    clearTimeout(timeout);
    timeout = setTimeout(later, wait);

    if (callNow) func.apply(context, args);
  };
};

...

debuncedHandlePress = debounce(this.handlePress, 500); // Now, when the button is pressed, it will call this function, instead of the original handlePress

But with this, the only thing I do is decrease the chance of getting messy results. That is, I still have the same problem as with the first code.

Any idea to do what I want in such a way that the results I get are ordered and avoiding the little wait for writing to the database?

Thank you.

解决方案

The solution is to disable the button immediately. Using setState, you cannot expect immediate update of isLinking, and that's why you are annoyed.One of the solution is to use flag variable instead of using state.

You can fix in this way.

 state = {
    isLiked: false,
 }

 constructor(props) {
    this.isLiking = false; <------------------------------------
 }
 

 handlePress = () => {
    this.isLiking = true; <------------------------------------
    this.setState(
      {
        isLiked: !this.state.isLiked,
      },
      this.handleLike
    );
  };

  handleLike = async () => {
    const { postId } = this.props;

    try {
      console.log(isLiked ? "Liking" : "Disliking"); 
      await db.processLike(postId);
    } catch (err) {
      // If an error has occurred, reverse the 'isLiked' state
      this.setState({
        isLiked: !this.state.isLiked,
      });

      // TODO - Alert the error to the user in a toast
      console.log(err);
    }

    this.isLiking = false; <------------------------------------

    console.log("DONE");
  };

这篇关于如何在 React (async/await) 中创建原子进程?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-20 20:45