如何实际使用上下文?

时间:2020-04-22 13:05:44

标签: reactjs react-props

编辑:使用钩子解决

我一直在疯狂地做这件事。我在另一个组件中必须使用道具的问题。我了解我应该使用上下文。

我已经遵循了一些教程,但是由于某些原因,我无法将其应用于自己的代码。

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

当我单击一个国家/地区时,我想在巨型机中显示数据库中的信息: https://imgur.com/eoftLW0

我想查看的数据: https://imgur.com/Vt9IEr0

问题是, 当我单击一个国家时,我必须将大陆设置为相应的大陆。首先,我想通过它作为道具,但是后来我建议使用上下文,现在我在这里。

编辑5: 我不确定上下文是否是正确的方法。一位朋友推荐我尝试一下,但无法进一步帮助我。

编辑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 个答案:

答案 0 :(得分:1)

假设您阅读了the docs about context API和其他一些资料。我将尝试涵盖我第一次使用上下文时遇到的一些遗漏部分。

  1. 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
}

  1. 必须在消费者的树中某个位置呈现消费者。
<MyContextProvider>
  <MyAppThatSomewhereHasAConsumer />
  // or may be directly <MyContextConsumer /> but the idea of the context is to be used in multiple parts
</MyContextProvider>

  1. 如果只有一个消费者,则可能不需要上下文,必须将状态定位在正确的位置。

  2. 在多个项目中使用Context api时,我使用了一个技巧,即如果我忘记将提供者放在正确的位置(也通知我的队友),我会发现一种很好的做法来通知我。我创建了一个钩子来使用我的上下文,即: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

a codesandbox demo如下所示:

codesandbox example

答案 1 :(得分:0)

答案 2 :(得分:0)

有一个库实际上使使用多个上下文https://www.npmjs.com/package/react-dynamic-context-provider更加容易。