Mir*_*run 101 asynchronous reactjs react-native
使用componentDidMount()作为一个异步函数的良好做法作出反应本地还是应该避免呢?
我需要从AsyncStorage组件安装时获取一些信息,但我知道实现这一点的唯一方法是使componentDidMount()函数异步.
async componentDidMount() {
let auth = await this.getAuth();
if (auth)
this.checkAuth(auth);
}
Run Code Online (Sandbox Code Playgroud)
这有什么问题,还有其他解决方案吗?
Cù *_*iếu 125
让我们首先指出差异并确定它如何引发麻烦.
以下是异步和"同步" componentDidMount()生命周期方法的代码:
// This is typescript code
componentDidMount(): void { /* do something */ }
async componentDidMount(): Promise<void> {
/* do something */
/* You can use "await" here */
}
Run Code Online (Sandbox Code Playgroud)
通过查看代码,我可以指出以下差异:
async关键字:在打字稿,这仅仅是一个代码标记.它做了两件事:
Promise<void>而不是void.如果您明确指定返回类型为非承诺(例如:void),则typescript将向您发出错误.await在方法中使用关键字.void为Promise<void>
async someMethod(): Promise<void> { await componentDidMount(); }您现在可以await在方法中使用关键字并暂时暂停其执行.像这样:
async componentDidMount(): Promise<void> {
const users = await axios.get<string>("http://localhost:9001/users");
const questions = await axios.get<string>("http://localhost:9001/questions");
// Sleep for 10 seconds
await new Promise(resolve => { setTimeout(resolve, 10000); });
// This line of code will be executed after 10+ seconds
this.setState({users, questions});
return Promise.resolve();
}
Run Code Online (Sandbox Code Playgroud)现在,他们怎么会引起麻烦?
async关键字绝对无害.我无法想象你需要调用componentDidMount()方法的任何情况,所以返回类型Promise<void>也是无害的.
调用返回类型为Promise<void>without awaitkeyword 的方法与调用具有返回类型的方法没有区别void.
由于componentDidMount()延迟执行后没有生命周期方法似乎非常安全.但是有一个问题.
比方说,以上this.setState({users, questions});将在10秒后执行.在延迟时间的中间,另一个......
this.setState({users: newerUsers, questions: newerQuestions});
...已成功执行并且DOM已更新.结果对用户可见.时钟继续滴答,10秒钟过去了.this.setState(...)然后执行延迟,并且DOM将再次更新,那个时间用旧用户和旧问题.用户也可以看到结果.
=>这是很安全的(我不知道约100%),使用async与componentDidMount()方法.我是它的忠实粉丝,到目前为止我还没有遇到任何让我头疼的问题.
你的代码很好,对我来说非常易读.看看这个Dale Jefferson的文章,他在那里展示了一个异步的componentDidMount例子,看起来也非常好.
但有些人会说,阅读代码的人可能会认为React对返回的承诺做了一些事情.
因此,对此代码的解释以及是否是一种良好的实践是非常个人化的.
如果您想要其他解决方案,可以使用promises.例如:
componentDidMount() {
fetch(this.getAuth())
.then(auth => {
if (auth) this.checkAuth(auth)
})
}
Run Code Online (Sandbox Code Playgroud)
当您使用componentDidMountwithoutasync关键字时,文档会这样说:
您可以在 componentDidMount() 中立即调用 setState()。它会触发额外的渲染,但它会在浏览器更新屏幕之前发生。
如果你使用async componentDidMount你会失去这个能力:在浏览器更新屏幕后会发生另一个渲染。但是imo,如果您正在考虑使用异步,例如获取数据,则无法避免浏览器将更新屏幕两次。在另一个世界,在浏览器更新屏幕之前暂停 componentDidMount 是不可能的
我做了一些研究,发现了一个重要的区别: React不会处理异步生命周期方法中的错误。
因此,如果您编写如下内容:
componentDidMount()
{
throw new Error('I crashed!');
}
Run Code Online (Sandbox Code Playgroud)
那么您的错误将被error boundry捕获,并且您可以对其进行处理并显示优美的消息。
如果我们这样更改代码:
async componentDidMount()
{
throw new Error('I crashed!');
}
Run Code Online (Sandbox Code Playgroud)
这等效于:
componentDidMount()
{
return Promise.reject(new Error('I crashed!'));
}
Run Code Online (Sandbox Code Playgroud)
这样您的错误就会被默默吞噬。对你感到羞耻,反应...
那么,我们如何处理错误呢?唯一的方法似乎是这样的显式捕获:
async componentDidMount()
{
try
{
await myAsyncFunction();
}
catch(error)
{
//...
}
}
Run Code Online (Sandbox Code Playgroud)
或像这样:
componentDidMount()
{
myAsyncFunction()
.catch(()=>
{
//...
});
}
Run Code Online (Sandbox Code Playgroud)
如果我们仍然希望我们的错误丰富错误边界,那么我可以考虑以下技巧:
render方法中抛出。例:
class BuggyComponent extends React.Component {
constructor(props) {
super(props);
this.state = { error: null };
}
buggyAsyncfunction(){ return Promise.reject(new Error('I crashed async!'));}
async componentDidMount() {
try
{
await this.buggyAsyncfunction();
}
catch(error)
{
this.setState({error: error});
}
}
render() {
if(this.state.error)
throw this.state.error;
return <h1>I am OK</h1>;
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
48143 次 |
| 最近记录: |