【问题标题】:How to pass route params in Context API如何在 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

【问题讨论】:

    标签: javascript reactjs react-router react-hooks


    【解决方案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 存储库以使其更清晰。

      1. 首先,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);
      

      ShowTheLocationwithRouter HOC 包裹起来,它将所有路线道具(比赛、历史、位置...)通过道具传递给ShowTheLocation。然后在ShowTheLocation 中,您可以使用props.match 之类的东西。够清楚吗?

      回到你的问题!您还没有通过withRouter 包装任何组件,是吗?坚持下去,玩得开心!你很快就会明白的!

      另外,请注意您必须将您的组件放在BrowserRouter 下才能使用 react-router 的东西

      1. 如果你想使用 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

      类似这样的:

      1. 在您的 Provider 组件所在的文件中导入 useParams
      2. 在您的 CountryContextProvider 中将其添加到组件的顶部:
      const { alpha3Code } = useParams();
      
      1. 更新需要props.matchuseEffect
      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
      猜你喜欢
      • 2021-08-13
      • 2020-07-23
      • 1970-01-01
      • 2020-10-20
      • 1970-01-01
      • 1970-01-01
      • 2015-10-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多