父组件用useMemo缓存子组件时,子组件如何通知父组件重新计算缓存
解决方案
首先纠正认知误区
你当前写法中,useMemo 缓存的只是 <Books /> 对应的JSX实例引用,不会阻断Books组件内部自身状态触发的更新。只要Books组件实例没有被卸载,内部调用setState触发的重渲染会正常执行,不需要父组件重新计算缓存。
只有当你需要替换整个Books组件实例(比如重置组件内部所有状态、更新传入Books的props)时,才需要父组件重新触发useMemo的计算,可通过以下两种方案实现:
方案1:给useMemo添加对应依赖项
如果Books组件的更新是由外部传入的props变化触发的,直接把这些props变量放到useMemo的依赖数组中即可,只要依赖项发生变化,useMemo就会自动重新计算生成新的组件实例:
function MyComponent() { const [activeTab, setActiveTab] = useState('Books'); // 假设bookId是传入Books组件的props,会动态变化 const [bookId, setBookId] = useState(1); // 把bookId加入依赖数组 const MemoizedBooks = useMemo(() => <Books bookId={bookId} />, [bookId]); const MemoizedRequests = useMemo(() => <Requests />, []); return ( <div>{activeTab === 'Books' ? MemoizedBooks : MemoizedRequests}</div> ) }
方案2:用版本号控制缓存刷新
如果需要由Books组件内部事件,或者父组件的其他操作触发缓存刷新,可以新增一个版本号状态作为依赖项,需要刷新时修改版本号即可:
function MyComponent() { const [activeTab, setActiveTab] = useState('Books'); // 版本号作为缓存的依赖项 const [booksVersion, setBooksVersion] = useState(0); const MemoizedBooks = useMemo(() => <Books refreshParent={refreshBooks} />, [booksVersion]); const MemoizedRequests = useMemo(() => <Requests />, []); // 调用该方法即可触发缓存重新计算 const refreshBooks = () => setBooksVersion(prev => prev + 1); return ( <div> <div>{activeTab === 'Books' ? MemoizedBooks : MemoizedRequests}</div> </div> ) }
如果需要在Books组件内部触发缓存刷新,把refreshBooks方法作为props传给Books组件,内部直接调用即可。
额外优化建议
如果你的场景允许两个组件同时挂载,直接用CSS的display: none控制显隐的性能会更优:组件不会频繁挂载卸载,内部状态会天然保留,不需要额外做缓存处理,切换的开销仅为DOM的样式更新。
内容的提问来源于stack exchange,提问作者Edmund1645
相关产品推荐
相关产品推荐

