Как передать параметры маршрута в Context API - PullRequest
0 голосов
/ 03 апреля 2020

Я использую 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]);

В компоненте, который я использую, он не работает, потому что он не знает, какие реквизиты .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, который я использую: здесь

Codesandbox Link

Project Github ссылка

Ответы [ 3 ]

3 голосов
/ 03 апреля 2020

В компоненте, который я использую, он не работает, потому что он не знает, что такое props.match.alpha3Code. Как я могу передать значение? Код alpha3Code поступает с URL-адреса: localhost: 3000 / country / asa, где asa - это код alpha3Code, как мне получить это значение ?

Я предполагаю, что root ваша проблема в этом. Вы не представляете, откуда берется параметр aplha3Code. Я углубился в ваше репозиторий GitHub, чтобы сделать его более понятным.

  1. Во-первых, match - это один из условий, предоставляемых реагирующим маршрутизатором. Когда вы используете что-то вроде props.match, props.history, props.location, ваш компонент должен быть заключен в 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 HO C, который пройдет все Маршрут реквизит (матч, история, местоположение ...) до ShowTheLocation через реквизит. Затем внутри ShowTheLocation вы можете использовать что-то вроде props.match. Достаточно ясно?

Итак, вернемся к вашей проблеме! Вы еще не завершили какие-либо компоненты к withRouter, не так ли? Придерживайтесь этого и повеселиться! Вы скоро это поймете!

Кроме того, имейте в виду, что вы должны поместить свой компонент под BrowserRouter, чтобы иметь возможность использовать вещи реагирующего маршрутизатора

Если вы хотите go с крючками, взгляните на этот очень полезный:

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 из ответа Порай:

Хотя я уже говорил Это заранее для вас, я просто чувствую, что вы не приложили достаточно усилий, чтобы go через то, что я сказал.

Также, пожалуйста, имейте в виду, что вы должны разместить ваш компонент под BrowserRouter, чтобы иметь возможность использовать реактивный маршрутизатор

В ваших codesandbox , это показывает ошибку Cannot read property 'match' of undefined. Хорошо, как я сказал выше, вы не переместили ContextCountryProvider в BrowserRouter, чтобы получить useRouter работу.

Я исправил это для вас, и на экране выскочил, пожалуйста, проверьте это в обновленный кодсанбокс здесь . Вы получите то, что вам нужно, в файле App. js.

Несмотря на то, что он по-прежнему выбрасывает некоторые ошибки Ax ios, я думаю, что моя работа выполнена. Остальное зависит от тебя.

1 голос
/ 05 апреля 2020

Вы можете обновить контекст из компонента, используя его, передав функцию установки, которая обновляет состояние контекста.

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);

Linked - работающая кодов и ящик реализации

0 голосов
/ 03 апреля 2020

Вы можете использовать useParams ловушку, чтобы получить все необходимое внутри вашего провайдера контекста. Документы

Примерно так:

  1. import useParams в файле, где ваш компонент поставщика
  2. в вашем CountryContextProvider добавить это вверху компонента:
const { alpha3Code } = useParams();
обновление useEffect, для которого необходимо props.match
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]);
...