使用useMemo后LoadedContent仍重复渲染,如何解决?
问题根源
你遇到的问题核心是:当切换到tab1时,LoadedContent组件被从DOM中卸载了。虽然你用useMemo缓存了JSX元素,但组件实例的生命周期由它是否挂载在DOM中决定——再次切回tab2时,组件会重新挂载,内部的请求逻辑自然会再次执行。useMemo只是缓存了JSX的描述对象,无法阻止组件的卸载和重新挂载。
解决方案
下面提供两种原生React的解决思路,都能实现只发起一次请求的需求:
方案1:通过样式控制显示/隐藏,不卸载组件
让两个组件始终挂载在DOM中,用display样式控制是否显示。这样LoadedContent只会挂载一次,内部请求也只会执行一次:
import React, { useState } from 'react'; import LoadedContent from './loadedContent'; import SimpleContent from './simpleContent'; const TabsPage = (props) => { const [tab, setTab] = useState("tab1"); return ( <div> <SimpleContent style={{ display: tab === "tab1" ? 'block' : 'none' }} /> <LoadedContent style={{ display: tab === "tab2" ? 'block' : 'none' }} /> </div> ) } export default TabsPage;
方案2:把请求逻辑提升到父组件,缓存数据
将数据请求的逻辑从LoadedContent移到父组件,用useEffect只请求一次,然后把数据传给子组件。这样不管子组件是否挂载,数据只会获取一次:
父组件修改:
import React, { useState, useEffect } from 'react'; import LoadedContent from './loadedContent'; import SimpleContent from './simpleContent'; const TabsPage = (props) => { const [tab, setTab] = useState("tab1"); const [loadedData, setLoadedData] = useState(null); const [isLoading, setIsLoading] = useState(true); // 仅在组件挂载时请求一次数据 useEffect(() => { // 替换为你的实际请求逻辑 fetch('/your-api-url') .then(res => res.json()) .then(data => { setLoadedData(data); setIsLoading(false); }) .catch(err => { console.error('请求失败:', err); setIsLoading(false); }); }, []); return ( <div> {tab === "tab1" ? ( <SimpleContent /> ) : ( isLoading ? <div>加载中...</div> : <LoadedContent data={loadedData} /> )} </div> ) } export default TabsPage;
子组件LoadedContent修改:
去掉内部的请求逻辑,直接接收父组件传递的数据:
// loadedContent.jsx const LoadedContent = ({ data }) => { // 直接渲染data内容 return <div>{/* 你的数据渲染逻辑 */}</div>; } export default LoadedContent;
补充说明
如果你的项目依赖第三方库,也可以使用react-keep-alive这类专门处理组件状态保留的库,但上述两种方案基于原生React,无需额外依赖,足够解决你的需求。
内容的提问来源于stack exchange,提问作者Gerry
相关产品推荐
相关产品推荐

