手写KeepAlive组件

0 阅读1分钟

一、React 默认“切换组件就会卸载”

{activeTab === 'A'
  ? <Counter name="A" />
  : <OtherCounter name="B" />
}

从 A 切到 B:A 卸载,B 挂载

因为在 React 眼里,这是两棵完全不同的树

二、KeepAlive 真正解决是:

让组件不要被卸载

组件实例始终存在于 Fiber 树里,只是隐藏

三、核心思想:缓存 children(React 元素)

if(!cache[activeId]){
  setCache((prev)=>({
    ...prev,
    [activeId]:children,
  }))
}

<Counter name="A" />本质是一个:ReactElement 对象

把这个对象保存起来

四、保存 children 就能“保活组件”

Object.entries(cache).map(([id,component])=>(
  <div
    key={id}
    style={{display:id === activeId ? 'block' : 'none'}}
  >
    {component}
  </div>
))

只要 component 被渲染过一次:

React 创建 Fiber
React 创建真实 DOM
React 建立 state
React 建立 effect

之后再也没有移除它,只是:display:none

五、完整 KeepAlive

const KeepAlive = ({ activeId, children }) => {
  const [cache, setCache] = useState({});

  useEffect(() => {
    setCache(prev => {
      if (prev[activeId]) return prev;
      return {
        ...prev,
        [activeId]: children,
      };
    });
  }, [activeId, children]);

  return (
    <>
      {Object.entries(cache).map(([id, component]) => (
        <div
          key={id}
          style={{ display: id === activeId ? 'block' : 'none' }}
        >
          {component}
        </div>
      ))}
    </>
  );
};

总结

childrenReactElementReactElement 可以被缓存,只要 ReactElement 一直被 render,组件就不会卸载,KeepAlive 的本质是:结构稳定,样式切换