React应用返回上一页时避免重复设置状态的方法
解决React从详情页返回主页重复发起API请求的问题
你的核心问题是:路由切换导致MainPage组件卸载后重新挂载,触发空依赖的useEffect重复发起API请求。以下是几种无需依赖LocalStorage的解决方案:
方案1:状态提升到路由父组件
将博客数据的状态提升到包裹路由的父组件(比如App),这样路由切换时父组件的状态不会丢失,MainPage重新挂载时直接复用已有数据:
// App.js import { useState, useEffect } from 'react'; import { Routes, Route } from 'react-router-dom'; import axios from 'axios'; import MainPage from './MainPage'; import BlogDetail from './BlogDetail'; function App() { const [blogs, setBlogs] = useState([]); useEffect(() => { // 仅当数据为空时发起请求 if (blogs.length === 0) { axios.get("/api/blogs/").then((res) => { setBlogs(res.data.blogs); }); } }, [blogs]); return ( <Routes> <Route path="/" element={<MainPage blogs={blogs} />} /> <Route path="/blog-detail/:id" element={<BlogDetail />} /> </Routes> ); } // MainPage.js import { Link } from 'react-router-dom'; function MainPage({ blogs }) { return ( <> {blogs.map((res) => ( <div key={res.id}> <b>{res.title}</b> <Link to={`blog-detail/${res.id}`}>Blog Detail</Link> </div> ))} </> ); }
方案2:使用useRef缓存请求状态
在MainPage组件内用useRef标记是否已完成请求,避免组件重新挂载时重复调用API:
import { useState, useEffect, useRef } from 'react'; import { Link } from 'react-router-dom'; import axios from 'axios'; function MainPage() { const [blogs, setBlogs] = useState([]); const hasFetched = useRef(false); // 标记是否已发起过请求 useEffect(() => { if (!hasFetched.current) { axios.get("/api/blogs/").then((res) => { setBlogs(res.data.blogs); hasFetched.current = true; }); } }, []); // 可选:添加手动刷新函数 const refreshBlogs = () => { axios.get("/api/blogs/").then((res) => { setBlogs(res.data.blogs); }); }; return ( <> {blogs.map((res) => ( <div key={res.id}> <b>{res.title}</b> <Link to={`blog-detail/${res.id}`}>Blog Detail</Link> </div> ))} <button onClick={refreshBlogs}>刷新博客</button> </> ); }
useRef的值在组件卸载后不会被重置,所以返回主页时hasFetched.current仍为true,不会重复请求。
方案3:使用数据请求库(React Query/SWR)
这类库自带请求缓存机制,无需手动处理状态,还支持自动重新验证、重试等功能,适合中大型应用:
以React Query为例:
- 安装依赖:
npm install @tanstack/react-query
- 配置并使用:
// App.js import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { Routes, Route } from 'react-router-dom'; import MainPage from './MainPage'; import BlogDetail from './BlogDetail'; const queryClient = new QueryClient(); function App() { return ( <QueryClientProvider client={queryClient}> <Routes> <Route path="/" element={<MainPage />} /> <Route path="/blog-detail/:id" element={<BlogDetail />} /> </Routes> </QueryClientProvider> ); } // MainPage.js import { useQuery } from '@tanstack/react-query'; import { Link } from 'react-router-dom'; import axios from 'axios'; function MainPage() { const { data: blogs = [] } = useQuery({ queryKey: ['blogs'], // 缓存唯一标识 queryFn: () => axios.get("/api/blogs/").then(res => res.data.blogs) }); return ( <> {blogs.map((res) => ( <div key={res.id}> <b>{res.title}</b> <Link to={`blog-detail/${res.id}`}>Blog Detail</Link> </div> ))} </> ); }
React Query会自动缓存请求结果,返回主页时直接复用缓存,无需重复发起API请求。
内容的提问来源于stack exchange,提问作者Xerali
相关产品推荐
相关产品推荐

