Reactjs 使用async componentDidMount()好吗?

Reactjs 使用async componentDidMount()好吗?,reactjs,asynchronous,react-native,Reactjs,Asynchronous,React Native,在React Native中使用componentDidMount()作为异步函数是一种很好的做法,还是应该避免 当组件装入时,我需要从AsyncStorage获取一些信息,但我知道的唯一方法是使componentDidMount()函数异步 async componentDidMount() { let auth = await this.getAuth(); if (auth) this.checkAuth(auth); } 这有什么问题吗?还有其他解决方

在React Native中使用
componentDidMount()
作为异步函数是一种很好的做法,还是应该避免

当组件装入时,我需要从
AsyncStorage
获取一些信息,但我知道的唯一方法是使
componentDidMount()
函数异步

async componentDidMount() {
    let auth = await this.getAuth();
    if (auth) 
        this.checkAuth(auth);
}

这有什么问题吗?还有其他解决方案吗?

您的代码很好,对我来说非常可读。在这里,他展示了一个async
componentDidMount
示例,看起来也很不错

但是有些人会说,阅读代码的人可能会认为React使用返回的承诺做了一些事情

因此,对这一准则的解释,以及它是否是一种良好的做法,是非常个人化的

如果您需要其他解决方案,可以使用。例如:

componentDidMount() {
    fetch(this.getAuth())
      .then(auth => {
          if (auth) this.checkAuth(auth)
      })
}

让我们从指出差异开始,并确定它如何会造成麻烦

下面是异步和“sync”的代码
componentDidMount()
life-cycle方法:

// This is typescript code
componentDidMount(): void { /* do something */ }

async componentDidMount(): Promise<void> {
    /* do something */
    /* You can use "await" here */
}
现在,他们怎么会制造麻烦呢?

  • async
    关键字绝对无害
  • 我无法想象在什么情况下需要调用
    componentDidMount()
    方法,因此返回类型
    Promise
    也是无害的

    调用返回类型为
    Promise
    而不使用
    wait
    关键字的方法与调用返回类型为
    void
    的方法没有区别

  • 由于
    componentDidMount()
    之后没有生命周期方法,因此延迟其执行似乎相当安全。但是有一个问题

    比方说,上面的
    this.setState({users,questions})将在10秒后执行。在延迟时间的中间,另一个…

    this.setState({users:newerUsers,questions:newerQuestions})

    。。。已成功执行,并且已更新DOM。结果对用户可见。时钟继续滴答作响,10秒过去了。然后将执行延迟的
    this.setState(…)
    ,DOM将再次更新,这一次将使用老用户和老问题。结果也将对用户可见

  • =>使用
    async
    componentDidMount()
    方法是非常安全的(我不确定大约100%)。我是它的忠实粉丝,到目前为止,我还没有遇到任何让我头疼的问题。

    更新:

    (我的身材:React 16,网页4,巴别塔7):

    使用Babel 7时,您会发现:

    使用此模式

    async componentDidMount() {
        try {
            const res = await fetch(config.discover.url);
            const data = await res.json();
            console.log(data);
        } catch(e) {
            console.error(e);
        }
    }
    
    componentDidMount() {
        fetch(config.discover.url)
        .then(res => res.json())
        .then(data => {
            console.log(data);
        })
        .catch(err => console.error(err));
    }
    
    您将遇到以下错误

    未捕获引用错误:未定义regeneratorRuntime

    在这种情况下,您需要安装babel插件转换运行时

    如果出于某种原因,您不希望安装上述软件包(babel插件转换运行时),那么您将希望坚持承诺模式

    async componentDidMount() {
        try {
            const res = await fetch(config.discover.url);
            const data = await res.json();
            console.log(data);
        } catch(e) {
            console.error(e);
        }
    }
    
    componentDidMount() {
        fetch(config.discover.url)
        .then(res => res.json())
        .then(data => {
            console.log(data);
        })
        .catch(err => console.error(err));
    }
    

    当您使用
    componentDidMount
    而不使用
    async
    关键字时,文档会这样说:

    您可以在componentDidMount()中立即调用setState()。它将触发额外的渲染,但会在浏览器更新屏幕之前发生


    如果使用
    async componentDidMount
    将失去此功能:在浏览器更新屏幕后将发生另一次渲染。但是,在我看来,如果您正在考虑使用异步,例如获取数据,则无法避免浏览器会更新屏幕两次。在另一个世界中,在浏览器更新屏幕之前暂停componentDidMount是不可能的

    我认为只要您知道自己在做什么就可以了。但这可能会让人困惑,因为
    async componentDidMount()
    componentWillUnmount
    运行并且该组件已卸载后仍然可以运行

    您可能还希望在
    componentDidMount
    中启动同步和异步任务。如果
    componentDidMount
    是异步的,则必须将所有同步代码放在第一个
    wait
    之前。对于某些人来说,第一个
    wait
    之前的代码是否同步运行可能并不明显。在这种情况下,我可能会保持
    componentDidMount
    同步,但让它调用sync和async方法


    无论您选择
    async componentDidMount(),ComponentDidMount中的异步加载是一种推荐的设计模式,因为React从传统的生命周期方法(componentWillMount、componentWillReceiveProps、componentWillUpdate)转移到异步呈现

    这篇博文非常有助于解释为什么这是安全的,并提供了ComponentDidMount中异步加载的示例:


    2020年4月更新: 最新的React 16.13.1中似乎解决了该问题,请参阅。感谢@abernier指出这一点


    我做了一些研究,发现了一个重要的区别: React不处理来自异步生命周期方法的错误。

    所以,如果你写这样的东西:

    componentDidMount()
    {
        throw new Error('I crashed!');
    }
    
    async componentDidMount()
    {
        throw new Error('I crashed!');
    }
    
    async componentDidMount()
    {
        try
        {
             await myAsyncFunction();
        }
        catch(error)
        {
            //...
        }
    }
    
    componentDidMount()
    {
        myAsyncFunction()
        .catch(()=>
        {
            //...
        });
    }
    
    然后您的错误将被捕获,您可以处理它并显示一条优美的消息

    如果我们像这样更改代码:

    componentDidMount()
    {
        throw new Error('I crashed!');
    }
    
    async componentDidMount()
    {
        throw new Error('I crashed!');
    }
    
    async componentDidMount()
    {
        try
        {
             await myAsyncFunction();
        }
        catch(error)
        {
            //...
        }
    }
    
    componentDidMount()
    {
        myAsyncFunction()
        .catch(()=>
        {
            //...
        });
    }
    
    这相当于:

    componentDidMount()
    {
        return Promise.reject(new Error('I crashed!'));
    }
    
    然后您的错误将被默默地吞没。你真丢脸,反应

    那么,我们如何处理错误呢?唯一的方法似乎是这样的明确捕获:

    componentDidMount()
    {
        throw new Error('I crashed!');
    }
    
    async componentDidMount()
    {
        throw new Error('I crashed!');
    }
    
    async componentDidMount()
    {
        try
        {
             await myAsyncFunction();
        }
        catch(error)
        {
            //...
        }
    }
    
    componentDidMount()
    {
        myAsyncFunction()
        .catch(()=>
        {
            //...
        });
    }
    
    或者像这样:

    componentDidMount()
    {
        throw new Error('I crashed!');
    }
    
    async componentDidMount()
    {
        throw new Error('I crashed!');
    }
    
    async componentDidMount()
    {
        try
        {
             await myAsyncFunction();
        }
        catch(error)
        {
            //...
        }
    }
    
    componentDidMount()
    {
        myAsyncFunction()
        .catch(()=>
        {
            //...
        });
    }
    
    如果我们仍然希望误差达到误差边界,我可以考虑以下技巧:

  • 捕获错误,使错误处理程序更改组件状态
  • 如果状态指示错误