--- title: Suspense 引发的样式丢失问题 date: 2023-07-07 author: zombieJ --- 我们知道,React 18 提供了一个专门为 CSS-IN-JS 使用的 `useInsertionEffect` hooks,它会比 `useLayoutEffect` 拥有更快的时序优先级,从而保证不会因为书写顺序而影响调用顺序的问题: ```tsx useLayoutEffect(() => { console.log('layout effect'); }, []); useInsertionEffect(() => { console.log('insertion effect'); }, []); // Console: // - insertion effect // - layout effect ``` 在早期 `@ant-design/cssinjs` 实现中,由于需要兼容 React 17 版本,我们并没有选择 `useInsertionEffect`,而是通过在 render 阶段添加样式的方式来模拟提前插入的效果: ```tsx // pseudocode. Not used in real world function useStyleInsertion(hash: string, counter: Record) { useMemo(() => { if (!counter[hash]) { // Insert only when current style not inserted } counter[hash] += 1; }, [hash]); useEffect( () => () => { counter[hash] -= 1; if (!counter[hash]) { // Remove if set to clear on destroy } }, [hash], ); } ``` 以上代码会对使用样式进行统计,如果发现当前样式没有被插入过,就会在 render 阶段插入样式,否则就不会插入。同样的,如果发现当前样式配置了未使用时卸载,则会在 effect 确认计数后清除。此外,还有一套类似的代码会监听 token 的变化,当存在多份 token 时会对不再使用的 token 对应的所有样式 `