Как на самом деле использовать контекст? - PullRequest
1 голос
/ 22 апреля 2020

Редактировать: Решено с помощью крючков

Я так схожу с ума. У меня есть проблема, где я должен использовать опору, в одном другом компоненте. Я понимаю, что я должен использовать контексты.

Я следовал некоторым учебникам, но по какой-то причине я не могу применить его к своему собственному коду.

export const FetchContinent = (props) => {
    console.log(props.continent)

return (
    <div>
        {props.continent}
    </div>
)
};

props.continent записывает именно то, что я хочу.

Я хочу использовать это точное значение в этом другом компоненте в качестве реквизита.

const JumbotronPage = (continent) => {

  return (
    <MDBContainer className="test">
      <MDBRow>
        <MDBCol>
          <MDBJumbotron className="text-center">
            <MDBCardTitle className="card-title h4 pb-2">
              <CountryList
                continent={["NA"]} //<-- HERE!!
                displayFields={["countryName"]}
              />
              <CountryList continent={["NA"]} displayFields={["revName"]} />
            </MDBCardTitle>

Поэтому я хочу использовать «props.continent», как (обратите внимание, что это в другом JS -файле и другой компонент):

               <CountryList
                continent={[props.continent]} //<-- HERE!!
                displayFields={["countryName"]}
              />

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

Редактировать: Обновленный код: FetchContinent:

export const FetchContext = createContext();

export const FetchContinent = (props) => (
    <FetchContext.Provider value={props}>
        {console.log("Fetch continent: " + props.continent)}
      {props.children}
    </FetchContext.Provider>
  );

Я хотел бы напечатать это значение в другом файле:


const JumbotronPage = (props) => {
  console.log("Props.continent: " + props.continent);
  const value = useContext(FetchContext);
  return (
    <FetchContext.Consumer>
      <h1>{value}</h1>
    </FetchContext.Consumer>
  );
};

Однако значение становится неопределенным.

Редактировать 2: Вот как я использую FetchContinent:

const Africa = ({}) => {
  return (
    <div>
      <VerContinentToolbar before="Memories" continent={["Africa"]} />
      <FetchContinent continent={["Africa"]} />

Редактировать 3: Полный код: JUMBOTRON (код, который я имел до того, как начал работать с контекстами):

const JumbotronPage = (props) => {

  console.log(<VerContinentToolbar props={props.props} />);
  console.log("fdfds");
  return (
    <MDBContainer className="test">
      <MDBRow>
        <MDBCol>
          <MDBJumbotron className="text-center">
            <MDBCardTitle className="card-title h4 pb-2">
              <CountryList continent="Africa" displayFields={["countryName"]} />
              <CountryList continent="Africa" displayFields={["revName"]} />
              <CountryList
                continent={props.continent}
                displayFields={["countryName"]}
              />
              <CountryList
                continent={props.continent}
                displayFields={["revName"]}
              />
            </MDBCardTitle>

            <MDBCardImage
              src="https://mdbootstrap.com/img/Photos/Slides/img%20(70).jpg"
              src="https://d2gg9evh47fn9z.cloudfront.net/800px_COLOURBOX32059289.jpg"
              className="img-fluid"
            />
            <MDBCardBody>
              hej
              <MDBCardTitle className="indigo-text h5 m-4">
                <CountryList continent="Africa" displayFields={["beerPrice"]} />
                <CountryList continent="Africa" displayFields={["foodPrice"]} />
                <CountryList
                  continent="Africa" 
                  continent={props.continent}
                  displayFields={["beerPrice"]}
                />
                <CountryList
                  continent={props.continent}
                  displayFields={["foodPrice"]}
                />
                <CountryList
                  continent={props.continent}
                  displayFields={["hostelPrice"]}
                />
                <CountryList continent="Africa" displayFields={["dest1"]} />
                <CountryList continent="Africa" displayFields={["dest2"]} />
                <CountryList continent="Africa" displayFields={["dest3"]} />
                <CountryList
                  continent={props.continent}
                  displayFields={["dest1"]}
                />
                <CountryList
                  continent={props.continent}
                  displayFields={["dest2"]}
                />
                <CountryList
                  continent={props.continent}
                  displayFields={["dest3"]}
                />
              </MDBCardTitle>
              <MDBCardText>
                <CountryList continent="Africa" displayFields={["review"]} />

Я хочу:

<CountryList
                  continent={props.continent}
                  displayFields={["dest3"]}
                />

props.continent для передачи из:

const Africa = ({}) => {

  return (
    <div>
      <VerContinentToolbar before="Memories" continent={["Africa"]} />
      <Breadcrumb continent="Africa" />

Этот компонент.

Редактировать 4: Итак, если я получу доступ к своему компоненту «Африка»: https://imgur.com/4LSPwS6 Я хотел бы загрузить каждую страну из моей базы данных с континентом «Африка»

Когда я нажимаю «Африка», я хочу видеть каждую страну в настоящее время. в базе данных, связанной с Африкой: https://imgur.com/v1dGE9J

Когда я нажимаю на страну, я хочу отобразить информацию из базы данных в виде jumbotron: https://imgur.com/eoftLW0

Данные, которые я хотел бы просмотреть: https://imgur.com/Vt9IEr0

Проблема в том, что, когда я нажимаю на страну, мне нужно установить континент на соответствующий континент , Сначала я хотел передать его как опору, но потом мне рекомендовали использовать контекст, и теперь я здесь.

Редактировать 5: Я не совсем уверен, является ли контекст контекстом go , Друг порекомендовал мне попробовать, но не смог мне помочь.

Редактировать 6: Список стран:

import React, { Component, useState, useEffect } from 'react'
import { Link } from 'react-router-dom';
import firebase from '../config'
import './Countries.css'



const useCountries = continent => {
    const [countries, setCountries] = useState([]);
    console.log("Country list: " + continent)

    useEffect(() => {
        firebase
            .firestore()
            .collection(continent[0])
            .onSnapshot((snapshot) => {
                const newCountries = snapshot.docs.map((doc) => ({

                    id: doc.id,

                    ...doc.data()

                }))
                setCountries(newCountries)

            })
    }, [])

    return countries
}



const CountryList = ({ continent, displayFields = [] }) => {
    const countries = useCountries(continent); // <--- Pass it in here

    return (
        <div className="countries">
            {countries.map(country => (
                <div key={country.id}>

                    <div className="entry">

                        {displayFields.includes("continent") && (
                            <div>Name of continent: {country.continent}</div>

                        )}
                        {displayFields.includes("revName") && (
                            <div>{country.revName}</div>
                        )}
                        {displayFields.includes("countryName") && (
                            <div><Link to={"./Jumbotron"}>{country.countryName}</Link></div>
                        )}
                        {displayFields.includes("dest1") && (
                            <div>Destination 1: {country.dest1}</div>
                        )}
                        {displayFields.includes("dest2") && (
                            <div>Destination 2: {country.dest2}</div>
                        )}
                        {displayFields.includes("dest3") && (
                            <div>Destination 3: {country.dest3}</div>
                        )}
                        {displayFields.includes("beerPrice") && (
                            <div>Beer price: {country.beerPrice}</div>
                        )}
                        {displayFields.includes("foodPrice") && (
                            <div>Food price: {country.foodPrice}</div>
                        )}
                        {displayFields.includes("hostelPrice") && (
                            <div>Hostel price: {country.hostelPrice}</div>
                        )}
                        {displayFields.includes("review") && <div>Review: {country.review}</div>}
                        {displayFields.includes("imgUrl") && <img src={country.url} alt="no-img" />}

                    </div>
                </div>

            ))}
        </div>
    );
};


export default CountryList

Спасибо,

Ответы [ 3 ]

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

Предполагается, что вы прочитали документы по контекстному API и некоторые другие источники. Я постараюсь охватить некоторые недостающие части, которые у меня были при работе с контекстом в первый раз.

  1. A Context состоит из двух частей: один поставщик и потребители. Поставщик является ответственным за хранение значений, и потребители получат эти значения и будут получать уведомления при каждом обновлении.
const MyContext = React.createContext(null);

// bellow code is for illustration only
const MyContextProdiver = ({ children }) => <MyContext.Provider value={{ continentsData: [] }}>{children}</MyContext.Provider>;

const MyContextConsumer = () => {
  const contextValue = React.useContext(MyContext);

  return null; // a react element must be returned here
}

Потребитель должен отображаться где-то в дереве в потребителе.
<MyContextProvider>
  <MyAppThatSomewhereHasAConsumer />
  // or may be directly <MyContextConsumer /> but the idea of the context is to be used in multiple parts
</MyContextProvider>

Если у вас есть только один потребитель, вам, вероятно, не нужен контекст, и вы должны найти свое состояние в нужном месте.

При использовании контекстного API для нескольких проекты, я использую трюк, который я считаю хорошей практикой, чтобы уведомить меня, если я забыл поставить провайдера в нужном месте (также, чтобы уведомить моих товарищей по команде). Я создаю ловушку для использования моего контекста, ie: useMyContext()

// this assumes that your context will always start with a truthy value
function useMyContext() {
  const myContextValue = React.useContext(MyContext);
  invariant(myContextValue, 'Have you forgot to put a <MyContext.Provider> somewhere up in the tree ?');
  // or simply put if (!myContextValue) throw new Error('there is no MyContext provider') 
  return myContextValue;
}

// later

const contextValue = useMyContext(); // and you will notified if you are in a tree where there is no provider

Проецируя эти заметки в соответствии с вашими требованиями, я предлагаю:

  1. Сделайте ContinentProvider, который обернет всех потребителей и предоставит им страны.
  2. Контекст может содержать данные для нескольких континентов, и потребитель может выбрать то, что ему нужно.
  3. Контекст только удерживает значений, он может быть более интеллектуальным и предоставлять функцию fetchContinentData (continentName), которая будет по требованию извлекать страны континента, если они еще не существуют в кэшированных данных
  4. Вы можете создать ловушку, которая напрямую обеспечивает страны континента: useContinentCountries который использует useContinentProvider

Вот демонстрация кодов и ящиков , которая выглядит следующим образом:

codesandbox example

0 голосов
/ 04 мая 2020

Есть библиотека, которая на самом деле облегчает использование нескольких контекстов https://www.npmjs.com/package/react-dynamic-context-provider.

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

Для реагирующего контекста нужен поставщик данных и потребитель.

enter image description here

https://de.reactjs.org/docs/context.html#contextprovider

https://de.reactjs.org/docs/context.html#contextconsumer

...