如何避免react-modal每次渲染时重新创建其body区域的List组件实例
问题根因
你遇到的问题核心来自两点:
- 未使用
useCallback包裹传递给List的onClick函数,每次状态更新都会生成新的函数引用,导致useMemo缓存失效 - ReactModal默认在模态框关闭时会卸载内部挂载的所有内容,再次打开就会重新创建组件实例
可落地实现方案
以下方案均不需要自行实现模态框,也不需要引入全局状态管理工具,可按需选择:
- 方案1:开启ReactModal的常驻挂载配置
直接给ReactModal组件添加keepMounted属性,即可让模态框关闭时仅隐藏内容,不卸载内部组件实例,修改Modal组件代码如下:
const Modal = ({ state, body, isOpen }) => { useEffect(() => { console.log("Modal is re-rendered"); }); return ( <div id="react modal wrapper" style={{ display: `${isOpen ? "block" : "none"}` }} > {/* 添加keepMounted属性 */} <ReactModal isOpen={isOpen} keepMounted={true}> <div> state is {state} <br /> {body} </div> </ReactModal> </div> ); };
- 方案2:优化函数引用与缓存逻辑
先在App层用useCallback包裹onClick函数,保证函数引用稳定,再修正Table层useMemo的依赖项:
首先修改App组件:
import { useEffect, useMemo, useState, useCallback } from "react"; const App = () => { const [state, setState] = useState(1); // 用useCallback包裹,保证函数引用不变 const onClick = useCallback(() => setState((v) => v + 1), [setState]); return ( <div> <button onClick={onClick}>Change state</button> <Table state={state} onClick={onClick} isOpen={state % 2 === 0} /> </div> ); };
再修改Table组件的useMemo依赖:
const Table = ({ state, onClick, isOpen }) => { useEffect(() => { console.log("Table is re-rendered"); }); // 依赖项加入稳定的onClick引用 const memorizedList = useMemo(() => <List onClick={onClick} />, [onClick]); return ( <div> state: {state} <Modal state={state} body={memorizedList} isOpen={isOpen} /> </div> ); };
- 方案3:状态提升
如果List内部有自定义状态,直接把这部分状态移动到Table或App层存储,通过props传递给List,就算List重新渲染,也能从props拿到最新的状态,不会丢失操作记录。
内容的提问来源于stack exchange,提问作者Trung Hieu Nguyen
相关产品推荐
相关产品推荐

