fre2 正式内置 suspense

321 阅读2分钟

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

github.com/yisar/fre

最后放一下 fre 的 github 地址,大家平时看 react 源码可以作为参考