以下是我编写的组件的简化。它有两个选项卡,根据选择的选项卡显示不同的内容(通过此处未包含的按钮完成)。 有两个子组件,一个仅显示静态内容的 SimpleContent 对象,以及一个必须离开的 LoadedContent 组件,从服务器调用以获取数据,然后呈现自身。我想做的只是让该服务器调用一次,所以我不想每次选择该选项卡时都重新渲染 LoadedContent。我希望它渲染 LoadedContent 组件一次,即使我单击选项卡 1,然后返回选项卡 2。
我认为使用 UseMemo 来包装 LoadedContent 组件会起作用,但事实并非如此 - 每次我单击选项卡 2 时,它都会重新加载内容。请问我该如何解决这个问题?
import React, { useState, useMemo } from 'react';
import LoadedContent from './loadedContent';
import SimpleContent from './simpleContent';
const TabsPage = (props) => {
const [tab, setTab] = useState("tab1");
const tab2Display = useMemo(() => {
return (
<LoadedContent />
)
}, [])
return (
<div>
{tab === "tab1" ?
<SimpleContent />
:
{tab2Display}
</div>
)
}
export default TabsPage;
为了确保 LoadedContent 组件只获取一次数据,您应该将加载逻辑移至父组件中,并将加载的数据存储在状态中。单独使用 useMemo 不会阻止重新渲染,因为它会在每次渲染时重新计算。以下是实现此方法的方法:
创建一个状态来保存加载的内容数据。 组件安装时使用效果来获取数据。 使用获取的数据渲染 LoadedContent。 这是 TabsPage 组件的更新版本:
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);
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch('YOUR_API_ENDPOINT'); // Replace with your API endpoint
const data = await response.json();
setLoadedData(data);
} catch (error) {
console.error('Error fetching data:', error);
}
};
// Fetch data only once when the component mounts
if (!loadedData) {
fetchData();
}
}, [loadedData]);
return (
<div>
<button onClick={() => setTab("tab1")}>Tab 1</button>
<button onClick={() => setTab("tab2")}>Tab 2</button>
{tab === "tab1" ?
<SimpleContent />
:
loadedData ? <LoadedContent data={loadedData} /> : <p>Loading...</p>
}
</div>
);
}
export default TabsPage;
在我看来,更好的解决方案是使用
react-query
,但需要更多重构。它们有一个 useQuery
钩子,可以从端点获取数据,然后缓存结果,因此您可以非常明确地知道何时要重新获取数据。 如果您有兴趣,这里是文档。