一、React 默认"切换组件就会卸载"
ini
{activeTab === 'A'
? <Counter name="A" />
: <OtherCounter name="B" />
}
从 A 切到 B:A 卸载,B 挂载
因为在 React 眼里,这是两棵完全不同的树。
二、KeepAlive 真正解决是:
让组件不要被卸载
组件实例始终存在于 Fiber 树里,只是隐藏
三、核心思想:缓存 children(React 元素)
scss
if(!cache[activeId]){
setCache((prev)=>({
...prev,
[activeId]:children,
}))
}
<Counter name="A" />本质是一个:ReactElement 对象
把这个对象保存起来。
四、保存 children 就能"保活组件"
css
Object.entries(cache).map(([id,component])=>(
<div
key={id}
style={{display:id === activeId ? 'block' : 'none'}}
>
{component}
</div>
))
只要 component 被渲染过一次:
perl
React 创建 Fiber
React 创建真实 DOM
React 建立 state
React 建立 effect
之后再也没有移除它 ,只是:display:none
五、完整 KeepAlive
ini
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>
))}
</>
);
};
总结
children是ReactElement,ReactElement可以被缓存,只要ReactElement一直被render,组件就不会卸载,KeepAlive 的本质是:结构稳定,样式切换