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

React动态内容组件缓存:避免重复渲染与API请求优化方案

解决菜单切换时内容组件重复渲染/API重复调用的问题

你的问题核心在于当前实现每次切换菜单时,都会卸载旧组件并挂载新组件,导致子组件里的API每次都重新调用。要让组件只渲染一次、切换时直接复用,最直接的方式是让所有内容组件始终保持挂载状态,仅通过显示/隐藏来切换视图,具体改造步骤如下:

1. 调整状态管理

把原来存储内容组件的content状态,改成存储当前选中的菜单key:

const [selectedKey, setSelectedKey] = useState<string>("monitor_progress");

2. 缓存组件实例(避免重复创建)

用useMemo缓存menuMap,确保组件实例不会因为父组件重新渲染而频繁创建:

const menuMap = useMemo(() => ({
  monitor_progress: <ProgressSection token={props.token} />,
  setup_experiment: <ExperimentSection token={props.token} />,
  define_subject: <SubjectsSection token={props.token} />,
  record_session: <SessionsSection token={props.token} />,
  analyze_results: <ResultsSection token={props.token} />,
}), [props.token]); // 仅当token变化时重新生成组件

3. 渲染所有组件并控制显示隐藏

不再只渲染当前选中的组件,而是把所有内容组件都渲染到DOM中,通过CSS的display属性控制显示/隐藏:

<Col span={21}>
  {Object.entries(menuMap).map(([key, component]) => (
    <div 
      key={key} 
      style={{ display: selectedKey === key ? 'block' : 'none' }}
    >
      {component}
    </div>
  ))}
</Col>

4. 更新菜单选择逻辑

handleSelect只需要更新选中的key即可:

const handleSelect = (key: string) => {
  setSelectedKey(key);
};

完整改造后的代码

function ProjectDashboard(props: sciOpsProps) {
    const menuItems = [
        {
            key: "monitor_progress",
            label: "Monitor Progress"
        },
        {
            key: "setup_experiment",
            label: "Setup Experiment"
        },
        {
            key: "define_subject",
            label: "Define Subject"
        },
        {
            key: "record_session",
            label: "Record Session"
        },
        {
            key: "analyze_results",
            label: "Analyze Results"
        }
    ];

    // 用useMemo缓存组件实例
    const menuMap = useMemo(() => ({
        monitor_progress: <ProgressSection token={props.token} />,
        setup_experiment: <ExperimentSection token={props.token} />,
        define_subject: <SubjectsSection token={props.token} />,
        record_session: <SessionsSection token={props.token} />,
        analyze_results: <ResultsSection token={props.token} />,
    }), [props.token]);

    // 存储选中的菜单key,而非组件实例
    const [selectedKey, setSelectedKey] = useState<string>("monitor_progress");

    const handleSelect = (key: string) => {
        setSelectedKey(key);
    };

    return (
        <Row>
            <Col span={3}>
                <Menu
                    onSelect={(menuItem) => handleSelect(menuItem.key)}
                    items={menuItems}
                    defaultSelectedKeys={["monitor_progress"]}
                    selectedKeys={[selectedKey]} // 同步选中状态
                />
            </Col>
            <Col span={21}>
                {/* 渲染所有组件,通过display控制显示隐藏 */}
                {Object.entries(menuMap).map(([key, component]) => (
                    <div 
                        key={key} 
                        style={{ display: selectedKey === key ? 'block' : 'none' }}
                    >
                        {component}
                    </div>
                ))}
            </Col>
        </Row>
    );
}

额外注意事项

确保你的子组件(比如ProgressSection)里的API调用是放在useEffect中,且依赖项设置正确,比如:

// ProgressSection示例
function ProgressSection({ token }) {
    useEffect(() => {
        // 这里调用API,仅在组件挂载时执行一次
        fetchYourData(token);
    }, []); // 空依赖确保只执行一次,若token变化需要重新调用则把token加入依赖

    // ...组件渲染逻辑
}

这样所有内容组件只会在页面加载时挂载一次,后续切换菜单只是显示/隐藏已挂载的组件,API不会重复调用,彻底解决耗时问题。

内容的提问来源于stack exchange,提问作者Adib Baji

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 13:30:41