我正在使用上下文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
alpha3Codeasa
在哪里,我如何获取此值?
基本上,我想做的是。我在主页上列出了国家/地区列表。现在我正在尝试获取有关单个国家/地区的更多信息。路由/country/:alpha3Code
从 API 获取alpha3Code
的位置。
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 在这里
代码沙盒链接
项目Github链接
您可以通过传递更新上下文状态的 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);
链接是一个有效的代码沙箱实现
在我使用的组件中,它不起作用,因为它不知道 props.match.alpha3Code是什么。如何传递值?这 alpha3Code 来自网址:localhost:3000/country/asa where asa 是 alpha3Code,我怎样才能得到这个值?
我想你问题的根源就是这个。您不知道aplha3Code
参数来自哪个。我已经深入研究了您的 GitHub 存储库以使其更清晰。
- 首先,
match
是 react-router 提供的条款之一。当你使用类似props.match, props.history, props.location
的东西时,你必须用withRouter
包裹你的组件,这是react-router
提供的高阶组件。在路由器上查看。例如,下面是 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
下才能使用反应路由器的东西
如果你想使用 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>;
}
更新 1 来自 Peoray 的回复:
这是出现问题的地方: 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();
...
}
更新 2 来自 Peorey 的回复:
虽然我已经提前为你说了,但我只是觉得你没有付出足够的努力来完成我说的话。
另外,请注意,您必须将组件放在BrowserRouter
能够使用反应路由器的东西
在代码沙盒中,它显示Cannot read property 'match' of undefined
错误。好的,正如我上面所说,您没有将ContextCountryProvider
移动到BrowserRouter
下以获得useRouter
工作。
我已经为您修复了它,并且屏幕弹出了,请在此处更新的代码sanbox中查看它。您将在App.js文件中获得所需的内容。
虽然它仍然在那里抛出一些 Axios 错误,但我认为我的工作已经完成。剩下的就看你了。
您可以使用useParams
钩子在上下文提供程序中获取所需的所有内容。文档
像这样:
- 在提供程序组件所在的文件中导入
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]);