You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何避免react-modal每次渲染时重新创建其body区域的List组件实例

问题根因

你遇到的问题核心来自两点:

  1. 未使用useCallback包裹传递给List的onClick函数,每次状态更新都会生成新的函数引用,导致useMemo缓存失效
  2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 10:21:03