如何通过React Router v6实现跨组件监听状态变化
解决方案:在React Router v6中让子组件监听父组件状态变化
针对你的场景,有两种简单且实用的方案可以实现Page组件监听App中searchQuery的变化:
方案一:使用React Context共享状态
这是最直接的跨组件状态共享方式,因为App作为父路由组件包裹着<Outlet>,通过Context可以将searchQuery的状态和更新方法传递给所有子路由组件(包括Page)。
步骤1:创建搜索状态Context
// SearchContext.tsx import { createContext, useContext, useState, ReactNode } from 'react'; type SearchContextType = { searchQuery: string; setSearchQuery: (query: string) => void; }; const SearchContext = createContext<SearchContextType | undefined>(undefined); export const SearchProvider = ({ children }: { children: ReactNode }) => { const [searchQuery, setSearchQuery] = useState<string>(""); return ( <SearchContext.Provider value={{ searchQuery, setSearchQuery }}> {children} </SearchContext.Provider> ); }; export const useSearch = () => { const context = useContext(SearchContext); if (!context) { throw new Error('useSearch must be used within a SearchProvider'); } return context; };
步骤2:在App组件中使用Provider
修改App.tsx,用SearchProvider包裹<Outlet>(或整个App内容):
// App.tsx import { useSearch } from './SearchContext'; import { Outlet } from 'react-router-dom'; function App() { const { searchQuery, setSearchQuery } = useSearch(); return ( <> <AppBar component="nav"> {/* 输入框直接使用Context里的setSearchQuery */} <input type="text" value={searchQuery} onChange={(e) => setSearchQuery(e.target.value)} placeholder="搜索..." /> </AppBar> <Outlet /> </> ); }
同时在路由外层包裹SearchProvider(index.tsx):
// index.tsx import { SearchProvider } from './SearchContext'; const router = createBrowserRouter( createRoutesFromElements( <Route path="/" element={<SearchProvider><App /></SearchProvider>}> <Route path="page" element={<Page />}></Route> </Route> ) );
步骤3:在Page组件中消费状态
// Page.tsx import { useSearch } from './SearchContext'; function Page() { const { searchQuery } = useSearch(); return ( <div> 当前搜索关键词:{searchQuery} {/* 这里可以直接使用searchQuery,它会自动跟随App中的变化更新 */} </div> ); }
方案二:将搜索状态同步到URL搜索参数
如果希望搜索状态能通过URL分享、刷新页面后保留,推荐使用React Router v6的useSearchParams钩子,将searchQuery和URL的查询参数绑定。
步骤1:在App组件中同步搜索状态到URL
// App.tsx import { Outlet, useSearchParams } from 'react-router-dom'; function App() { const [searchParams, setSearchParams] = useSearchParams(); // 从URL参数中读取初始搜索值 const searchQuery = searchParams.get('q') || ""; const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => { const query = e.target.value; if (query) { setSearchParams({ q: query }); } else { // 清空搜索参数 searchParams.delete('q'); setSearchParams(searchParams); } }; return ( <> <AppBar component="nav"> <input type="text" value={searchQuery} onChange={handleSearchChange} placeholder="搜索..." /> </AppBar> <Outlet /> </> ); }
步骤2:在Page组件中监听URL参数变化
// Page.tsx import { useSearchParams } from 'react-router-dom'; function Page() { const [searchParams] = useSearchParams(); const searchQuery = searchParams.get('q') || ""; return ( <div> 当前搜索关键词:{searchQuery} {/* 当URL中的q参数变化时,searchQuery会自动更新 */} </div> ); }
方案对比
- React Context方案:适合不需要将搜索状态同步到URL的场景,实现简单,状态更新更直接。
- URL搜索参数方案:适合需要分享搜索结果链接、刷新页面保留状态的场景,符合路由的设计语义。
内容的提问来源于stack exchange,提问作者Eric
相关产品推荐
相关产品推荐

