halo 大家好,我是 132,今天给 fre 提了一个很重要的 pr,也就是内置 Suspense 组件
过去我一直没有内置 Suspense,是因为我一直不知道这玩意和普通 loading 有什么区别
但是因为今年很流行 sssr,这玩意 Suspense 是前提,所以我不得不内置它
what is suspense?
import { lazy, Suspense } from 'fre'
const OtherComponent = lazy(() => import('./OtherComponent'));
function MyComponent() {
return (
<div>
<Suspense fallback={<div>Loading...</div>}>
<OtherComponent />
</Suspense>
</div>
)
}
其实说白了是一种 loading 组件的“链表实现”,当渲染到 Lazy 组件的时候中断,然后链表回退到 Suspense 组件,并改变 child,渲染出 fallback 的内容
它利用了链表的中断、回退、更换指针,三个特性,所以被称之为“突破”
suspense 和 loading 组件的区别
实际上从功能上来说,suspense 组件和 loading 没有太多区别
因为 useEffect + setState 本身就是异步的
我之前写了个一个简单的外置实现
export function Suspense(props) {
const [suspend, setSuspend] = useState(false)
useEffect(current => {
Promise.all(current.promises).then(() => setSuspend(true))
}, [])
return [props.children, !suspend && props.fallback]
}
是的你没看错,在 fre 中外置 suspense 实现也就二十行代码
那么问题来了,如果内置,还是这么实现吗?
答案当然不是
export function Suspense(props){
return props.children
}
内置只需要一行代码,哈哈哈哈哈,这种组件其实蛮多的,比如 Fragment 也是这样
在 fre 或 react 中,这被称为边界组件,意思是它只提供一个标记,然后和解调度的时候根据标记干活
这个工作其实就是在恰当时机回退和更换链表指针
也就是说,只需要在 Lazy 组件渲染的时候,回退到 Suspense 组件,并将 child 指针指向 fallback 即可
<Suspense>
<template #default>
<article-info/>
</template>
<template #fallback>
<div>Loading…</div>
</template>
</Suspense>
在 vue 或 preact 等同步框架中,他们没有链表不能回退,通常实现方式是设置两个占位,然后根据某个内置 state 标记来决定渲染某个占位,更像是传统 loading 组件
这是两种完全不同的实现方式,虽然最终都能良好工作,但本质不同
总结
大家肯定要问,为什么这么着急内置 suspense,说好的 1kb 呢?
这是因为今年大家都在搞流式 ssr,这玩意依赖 Suspense,我也想搞
另外,内置 suspense 意味着,这个功能我会自己维护了,大家可以放心使用
可惜的是这样一来就彻底 2kb 了,搞死嘞o(╥﹏╥)o
最后放一下 fre 的 github 地址,大家平时看 react 源码可以作为参考