大家好,俺是 132,俺发现网上 Suspense 的文章很多,但没有一篇是可以说出重点
Suspense 和 Loading 组件的区别?
这是第一个重点,如果让你封装一个传统的 Loading 组件,可能长下面这个样子:
import useSWR from 'swr'
function Profile () {
const { data, error } = useSWR('/api/user', fetch)
if (error) return <div>failed to load</div>
if (!data) return <div>loading...</div>
return <div>hello {data.name}!</div>
}
而 Suspense 是这样子的:
import {Suspense, lazy} from 'fre'
const LazyComponent = lazy(Component)
function App() {
return <Suspense fallback={<div>Loading...</div>}>
<LazyComponent/>
</Suspense>
}
大家有没有想过,普通的 loading 组件和 Suspense 有什么不同?
这其实是 Suspense 的本质之一:兜底
普通的 loading 组件,它可以控制的只是自己本身,自己是否有数据,自己是否展示 loading
<LoadingComponent/>
<LoadingComponent/>
<LoadingComponent/>
以上,如果这三个组件的数据都没有准备好,此时页面上应该是有三个 loading 代码块,而且等数据准备好,三个组件都要刷新一次
如果使用 Suspense 进行包裹,那么页面上将会只有一个 loading,而且只需要刷新 Suspense 一次就好了
Vue Suspense 和 Fre Suspense 有什么不同?
这就涉及到了,兜底的实现方式
我们怎样知道孩子是否全部渲染完成呢?有两种方式
第一种是 async 和 await
async function render(component){
await Promise.all(component.children.map(render))
return await updateComponent(component)
}
我们在递归渲染的过程中,父组件的渲染必须等待子组件渲染完成,变相的实现了 react fiber 的潜水机制:
我之前在 berial 尝试过这个思路,感兴趣的可以看看:zhuanlan.zhihu.com/p/288513354
vue 也算是这个思路,只不过它没有一个潜水过程,算是降级版
但无论如何,基于 async 和 await 确实可以实现兜底
但我们今天想说的是,另一种兜底方案,也就是 fre/react 的方案
componentDidCatch(err) {
if (isPromise(err)) {
this.setState({ pending: true })
err.then(() => {
this.setState({ pending: false })
}).catch(err => {
this.setState({ error })
})
} else {
throw err
}
}
通过 try catch 的机制,实现兜底
子组件 catch 到了 promise,我就把这个组件放到最近的 Suspense 里,然后链表回退,渲染 loading 占位符
巧妙地利用了 throw try catch 的机制
这样做的好处,一方面不需要 async/await 语法糖,也没有传染性
一方面还符合 algebraic effects 的思想
这是 Suspense 第二点奇妙之处
Suspense 为什么是组件而不是 hook?
开头我们也提到了,swr 这种 hooks api 也很好用,那么为什么 Suspense 要设计为组件呢?
像 Suspense 这类组件,其实都没有实现逻辑的,它们只是提供一个标记功能
这类组件被称为边界组件,ErrorBoundary,Suspense,Fragment 都是这样的
但有了这些“标记”,我们在遍历数据结构的时候,就可以按照边界进行拆分
比如 react 最新的 fizz 架构,就是根据 Suspense 边界,拆分 segment,最终实现流式渲染
如果是 hooks API 的话就做不到标记功能了
总结
从三个角度分析 Suspense 组件,总的来说这玩意真的设计的很赞
fre 是我写的 react like 框架,最近也完美支持了 Suspense,之所以这么急切地实现它,也是为了接下来的 fizz 架构做铺垫
fizz 架构是 react 下一个堪比 fiber 的新突破
之后有机会我会再来更新文章
最后走过路过不要错过,对 react 源码感兴趣的小伙伴,快来读 fre,欢迎 star 呀