我正在使用 React 和 React Router。我在 App.js 中定义了所有数据获取和路由。
我正在单击嵌套子组件 <ChildOfChild />
中的按钮,当单击按钮(使用 Context API 向下传递函数)时刷新我的数据,并在我的顶级组件 App.js 中发生获取请求(我有一个console.log 那里,所以它肯定会在点击时获取)。但是刷新后的数据状态永远不会到达 <ChildOfChild />
组件。相反,它会刷新旧状态。我究竟做错了什么。我如何确保 <Link>
内的状态在状态更新时刷新。
我希望 item.name
值在按钮点击时更新。
应用组件
import React, {useEffect, useState} from "react";
export const FetchContext = React.createContext();
export const DataContext = React.createContext();
const App = () => {
const [data, setData] = useState([false, "idle", [], null]);
useEffect(() => {
fetchData()
}, []);
const fetchData = async () => {
setData([true, "fetching", [], null]);
try {
const res = await axios.get(
`${process.env.REACT_APP_API}/api/sample/`,
{
headers: { Authorization: `AUTHTOKEN` },
}
);
console.log("APP.js - FETCH DATA", res.data)
setData([false, "fetched", res.data, null]);
} catch (err) {
setData([false, "fetched", [], err]);
}
};
return (
<Router>
<DataContext.Provider value={data}>
<FetchContext.Provider value={fetchData}>
<Switch>
<Route exact path="/sample-page/" component={Child} />
<Route exact path="/sample-page/:id" component={ChildOfChild} />
</Switch>
</FetchContext.Provider>
</DataContext.Provider>
</Router>
)
}
子组件
import { DataContext } from "../App";
const Child = () => {
const [isDataLoading, dataStatus, data, dataFetchError] = useContext(DataContext);
const [projectsData, setProjectsData] = useState([]);
{
data.map((item) => (
<Link
to={{
pathname: `/sampe-page/${item.id}`,
state: { item: item },
}}
>
{item.name}
</Link>
));
}
子组件的子组件
import { FetchContext } from "../App";
const ChildOfChild = (props) => {
const getData = useContext(FetchContext);
const [item, setItem] = useState({});
const [isItemLoaded, setIsItemLoaded] = useState(false);
useEffect(() => {
if (props.location.state.item) {
setItem(props.location.state.item);
setIsItemLoaded(true);
}
}, [props]);
return (
<div>
<button onClick={() => getData()}Refresh Data</button>
<div>{item.name}</div>
</div>
)
}
答案 0 :(得分:0)
ChildOfChild
呈现的特定数据项仅通过从 "/sample-page/"
到 "/sample-page/:id"
的路由转换发送,并且 ChildOfChild
在本地状态缓存它的副本。更新 data
中的 DataContext
状态不会更新 ChildOfChild
持有的本地化副本。
由于您已经在唯一标识它的路径上呈现 ChildOfChild
,(回想一下 Child
PUSHed to "/sample-page/${item.id}"
)您可以使用该路线的 id
从 DataContext
访问特定数据项。无需在路由状态下也发送整个数据项。
孩子
只需按项目 id
链接到新页面。
<Link to={`/sampe-page/${item.id}`}>{item.name}</Link>
ChildOfChild
通过 DataContext
钩子将 useContext
添加到组件中。
使用 props.match
访问路由的 id
匹配参数。
import { FetchContext } from "../App";
import { DataContext } from "../App";
const ChildOfChild = (props) => {
const getData = useContext(FetchContext);
const [,, data ] = useContext(DataContext);
const [item, setItem] = useState({});
const [isItemLoaded, setIsItemLoaded] = useState(false);
useEffect(() => {
const { match: { params: { id } } } = props;
if (id) {
setItem(data.find(item => item.id === id));
setIsItemLoaded(true);
}
}, [data, props]);
return (
<div>
<button onClick={getData}Refresh Data<button />
<div>{item?.name}<div>
</div>
)
}
useEffect
将确保当来自上下文或道具的 data
中的一个或两个更新时,item
状态将更新为最新的 data
和 id
参数。
关于使用 Switch
组件的旁注,路由路径顺序和特异性很重要。 Switch
将匹配并呈现与路径匹配的第一个组件。您将希望在 less 特定路径之前对 more 特定路径进行排序。这也使您无需为每个 exact
添加 Route
属性。现在,Switch
可以尝试在不太具体的路径“/sample-page”之前匹配更具体的路径“/sample-page/123”。
<Router>
<DataContext.Provider value={data}>
<FetchContext.Provider value={fetchData}>
<Switch>
<Route path="/sample-page/:id" component={ChildOfChild} />
<Route path="/sample-page/" component={Child} />
</Switch>
</FetchContext.Provider>
</DataContext.Provider>
</Router>
答案 1 :(得分:-1)
我刚刚在这里重写了您的代码,我使用了 randomuser.me/api
来获取数据
看看这里,它有一些拼写错误,但在这里看起来不错
https://codesandbox.io/s/modest-paper-nde5c?file=/src/Child.js