React中使用Context无法向路由页面组件传递数据求助
问题原因与解决方案
问题原因
- Context作用域不覆盖目标组件:你的
Context.Provider仅在Overview组件内部,而History是独立的路由页面组件。当从/跳转到/history时,Overview组件会被卸载,History组件不在Provider的包裹层级中,只能读取到Context的默认空数组。 - 状态更新存在闭包隐患:
handleSubmit中用[...history, clonedValues]更新状态,连续提交时会因闭包捕获旧状态,导致历史记录更新不完整。
解决步骤
1. 重构Context,提升Provider层级
将Context的Provider移到路由组件的外层,确保所有需要访问历史数据的路由组件都在其作用域内。建议单独抽离Context文件,便于维护:
// HistoryContext.tsx import { createContext, useContext, useState, ReactNode, Dispatch, SetStateAction } from 'react'; export type HistoryData = { input: string; date: string; }; type ContextProviderType = { history: HistoryData[]; setHistory: Dispatch<SetStateAction<HistoryData[]>>; }; export const HistoryContext = createContext<ContextProviderType>({ history: [], setHistory: () => {}, }); export const HistoryProvider = ({ children }: { children: ReactNode }) => { const [history, setHistory] = useState<HistoryData[]>([]); return ( <HistoryContext.Provider value={{ history, setHistory }}> {children} </HistoryContext.Provider> ); }; export const useHistoryData = () => useContext(HistoryContext);
2. 在App组件中用Provider包裹路由
修改App.tsx,让所有路由组件都能访问Context:
import { Routes, Route } from 'react-router-dom'; import { Overview } from './Overview'; import { History } from './History'; import { HistoryProvider } from './HistoryContext'; function App() { return ( <HistoryProvider> <Routes> <Route path="/" element={<Overview />} /> <Route path="/history" element={<History />} /> </Routes> </HistoryProvider> ); } export default App;
3. 修改Overview组件的状态更新逻辑
移除Overview内部的history状态,直接从Context获取setHistory,并改用函数式更新避免闭包问题:
// Overview.tsx import { useState } from 'react'; import axios from 'axios'; import { useHistoryData } from './HistoryContext'; type Props = { children?: React.ReactNode; }; export const Overview = ({ children }: Props) => { const [inputText, setInputText] = useState(''); const [data, setData] = useState<any[]>([]); const [loading, setLoading] = useState(false); const { setHistory } = useHistoryData(); const handleSubmit = (e: React.MouseEvent<HTMLElement>) => { e.preventDefault(); setLoading(false); axios .get(`https://api.github.com/users/${inputText}/repos`) .then((response) => { setData(response.data); }) .catch((error) => { console.log('error', error); setLoading(true); }); // 函数式更新获取最新历史状态 setHistory(prevHistory => [ ...prevHistory, { input: inputText, date: new Date().toLocaleString() } ]); }; return ( // 保留原有的输入框、提交按钮等UI内容 <div> <input type="text" value={inputText} onChange={(e) => setInputText(e.target.value)} /> <button onClick={handleSubmit}>查询</button> {/* 其他组件内容 */} </div> ); };
4. History组件正常读取Context数据
// History.tsx import { useHistoryData } from './HistoryContext'; const History = () => { const { history } = useHistoryData(); return ( <div> <h2>查询历史</h2> {history.map((item, index) => ( <div key={index} style={{ margin: '10px 0', padding: '10px', border: '1px solid #eee' }}> <p>输入内容: {item.input}</p> <p>操作时间: {item.date}</p> </div> ))} </div> ); }; export default History;
内容的提问来源于stack exchange,提问作者kukri
相关产品推荐
相关产品推荐

