如何在 Context API 中传递路由参数
Posted
技术标签:
【中文标题】如何在 Context API 中传递路由参数【英文标题】:How to pass route params in Context API 【发布时间】:2020-07-15 03:01:40 【问题描述】:我正在使用上下文 API,我的上下文文件中有这个:
useEffect(() =>
async function getSingleCountryData()
const result = await axios(
`https://restcountries.eu/rest/v2/alpha/$props.match.alpha3Code.toLowerCase()`
);
console.log(result)
setCountry(result.data);
if (props.match) getSingleCountryData();
, [props.match]);
在我正在使用的组件中,它不起作用,因为它不知道 props.match.alpha3Code 是什么。我怎样才能传递价值? alpha3Code 来自 URL:localhost:3000/country/asa
其中asa
是 alpha3Code,我怎样才能得到这个值?
基本上,我想做的是。我有一个我在主页上列出的国家列表。现在,我正在尝试获取有关单个国家/地区的更多信息。路由是/country/:alpha3Code
,其中alpha3Code
是从API 获取的。
FWIW,这是我的完整上下文文件:
import React, useState, createContext, useEffect from 'react';
import axios from 'axios';
export const CountryContext = createContext();
export default function CountryContextProvider(props)
const [countries, setCountries] = useState([]);
const [country, setCountry] = useState([]);
useEffect(() =>
const getCountryData = async () =>
const result = await axios.get(
'https://cors-anywhere.herokuapp.com/https://restcountries.eu/rest/v2/all'
);
setCountries(result.data);
;
getCountryData();
, []);
useEffect(() =>
async function getSingleCountryData()
const result = await axios(
`https://restcountries.eu/rest/v2/alpha/$props.match.alpha3Code.toLowerCase()`
);
console.log(result)
setCountry(result.data);
if (props.match) getSingleCountryData();
, [props.match]);
return (
<CountryContext.Provider value= countries, country >
props.children
</CountryContext.Provider>
);
在我使用country
的组件中,我有:
const country = useContext(CountryContext);
我知道我可以从组件本身执行此操作,但我正在学习如何使用上下文 API,因此我正在处理我的上下文中的所有 API 调用。
我正在使用的 API 是 here
Codesandbox Link
项目 Github link
【问题讨论】:
【参考方案1】:您可以通过传递一个更新上下文状态的 setter 函数来从使用它的组件更新上下文。
export default function CountryContextProvider( children )
const [countries, setCountries] = useState([]);
const [country, setCountry] = useState([]);
const [path, setPath] = useState('');
useEffect(() =>
async function getSingleCountryData()
const result = await axios(`your/request/for/$path`);
setCountry(result.data);
if(path) getSingleCountryData();
, [path]);
return (
<CountryContext.Provider value= countries, country, setPath >
children
</CountryContext.Provider>
);
现在使用 setPath
在挂载此组件后使用路由匹配更新请求端点。
const Details = ( match ) =>
const
params: alpha3Code
= match;
const country, setPath = useContext(CountryContext);
useEffect(() =>
setPath(alpha3Code);
, [alpha3Code]);
return (
<main>Some JSX here</main>
);
;
export default withRouter(Details);
链接是一个有效的codesandbox implementation
【讨论】:
【参考方案2】:在我正在使用的组件中,它不起作用,因为它不知道 props.match.alpha3Code 是什么。我怎样才能传递价值?这 alpha3Code 来自 URL:localhost:3000/country/asa 其中 asa 是 alpha3Code,我怎样才能得到这个值?
我猜你的问题的根源是这个。您不知道aplha3Code
参数来自哪个。我已经深入研究了您的 GitHub 存储库以使其更清晰。
-
首先,
match
是 react-router 提供的术语之一。当您使用props.match, props.history, props.location
之类的东西时,您的组件必须由withRouter
包裹,这是react-router
提供的高阶组件。查看withRouter。例如,下面是 react-router 提供的 withRouter
用法:
// A simple component that shows the pathname of the current location
class ShowTheLocation extends React.Component
render()
const match, location, history = this.props;
return <div>You are now at location.pathname</div>;
const ShowTheLocationWithRouter = withRouter(ShowTheLocation);
ShowTheLocation
被withRouter
HOC 包裹起来,它将所有路线道具(比赛、历史、位置...)通过道具传递给ShowTheLocation
。然后在ShowTheLocation
中,您可以使用props.match
之类的东西。够清楚吗?
回到你的问题!您还没有通过withRouter
包装任何组件,是吗?坚持下去,玩得开心!你很快就会明白的!
另外,请注意您必须将您的组件放在BrowserRouter
下才能使用 react-router 的东西
如果你想使用 Hooks,请看看这个超级有用的:
https://usehooks.com/useRouter/
它将所有useParams, useLocation, useHistory, and use useRouteMatch
挂钩包装成一个useRouter
,只公开我们需要的数据和方法。然后,例如,在你的组件内部,这样做:
import useRouter from "./myCustomHooks";
const ShowMeTheCode = () =>
const router = useRouter();
return <div>This is my alpha3Code: router.math.params.alpha3Code</div>;
Peoray 回复中的更新 1:
这是出现问题的地方: https://github.com/peoray/where-in-the-world/blob/cb09871fefb2f58f5cf0a4f1db3db2cc5227dfbe/src/pages/Details.js#L6
你应该避免像这样直接调用useContext()
。看看我下面的例子:
// CountryContext.js
import useContext, createContext from "react";
const CountryContext = createContext();
export const useCountryContext = () => useContext(CountryContext);
相反,您应该使用上面的useCountryContext
之类的自定义钩子来包装它。然后,在您的 Details
组件中,导入它并执行以下操作:
import React, from 'react';
import useCountryContext from '../contexts/CountryContext';
const Details = (props) =>
const country = useCountryContext();
...
Peoray 回复中的更新 2:
虽然我已经提前给你说了,但我只是觉得你没有付出足够的努力去完成我所说的。
另外,请注意您必须将您的组件放在
BrowserRouter
能够使用 react-router 的东西
在您的codesandbox 中,它显示Cannot read property 'match' of undefined
错误。好的,正如我上面所说,您还没有将ContextCountryProvider
移动到BrowserRouter
下以获得useRouter
工作。
我已经给你修好了,弹出了这个界面,请到updated codesanbox here查看。您将在 App.js 文件中获得所需的内容。
虽然它仍然会在那里抛出一些 Axios 错误,但我认为我的工作已经完成。剩下的就看你自己了。
【讨论】:
我尝试了您的建议,但没有成功。得到TypeError: useContext(...) is undefined
。不确定,如果我做得对。如果你想看看,我更新了 repo :)
首先,我认为你对 React 和 react-router 还是很陌生。因此,您应该删除 Context API,并首先使用 react-router 之类的东西,例如 withRouter
HOC。一旦你习惯了 React 世界,这就是 Context API、Hooks 来拯救的时候。如果您觉得我的建议有用,请点赞并标记接受!
您好,我确实查看了您的更新。我想我在这里得到它。等待我的更新!
@Peoray 嘿,我已经更新了我的答案。详情请查看Update 1 from Peoray's reply
。我想现在一切都好。如果您觉得有用,请不要忘记点赞并标记接受!
你试过这个并且成功了吗?因为之前的方法对Home.js
文件非常有效。另外,我对 React 并不陌生 :),只是对更新不熟悉,我的日常工作是 Vue,所以我正在努力恢复使用 React 的速度 :)【参考方案3】:
您可以使用useParams
钩子在上下文提供程序中获取所需的一切。 Docs
类似这样的:
-
在您的 Provider 组件所在的文件中导入
useParams
在您的 CountryContextProvider
中将其添加到组件的顶部:
const alpha3Code = useParams();
-
更新需要
props.match
的useEffect
useEffect(() =>
async function getSingleCountryData()
const result = await axios(
`https://restcountries.eu/rest/v2/alpha/$alpha3Code.toLowerCase()`
);
console.log(result)
setCountry(result.data);
if (alpha3Code) getSingleCountryData(); // or if you need `match` - do not destructure useParams()
, [alpha3Code]);
【讨论】:
如果我在 Provider 组件所在的文件中导入 useParams,在我的例子中是:src/pages/Details.js
,我得到一个已定义但未使用的文件,我该如何使用它?在我的仓库中,我使用的是props.match
,但什么也没发生,仍然返回空
它在第 2 步中说:“在您的 CountryContextProvider 中将其添加到 ...”
对不起,我不明白你的意思:(
这意味着它应该在这个大括号内:export default function CountryContextProvider(props) ...
在useState
行之前或之后
我收到了一个:TypeError: useContext(...) is undefined
以上是关于如何在 Context API 中传递路由参数的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 useEffect 和 Context API 来检查用户是不是登录并保护路由?
在组件之间路由时如何保持 React 新的 Context API 状态?
如何使用 Context API 将单个 Socket IO 实例传递给页面?
在 React.js 的父组件中使用 react-router 时,如何使用 react context API 将数据从父组件传递到子组件?