如何实际使用上下文?
How to actually use context?
编辑:使用钩子解决
我一直在疯狂地做这件事。我有一个问题,我必须在另一个组件中使用道具。我知道我应该使用上下文。
我遵循了一些教程,但由于某些原因,我无法将其应用到我自己的代码中。
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"]}
/>
我觉得我已经翻遍了所有的石头,但我想不出一个解决办法。
我清理了失败的尝试以使代码更具可读性。
编辑:
更新代码:
获取大陆:
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:
所以,如果我访问我的组件 "Africa":
https://imgur.com/4LSPwS6
我想从我的数据库中加载每个国家/地区 "Africa"
当我单击 "Africa" 时,我想查看当前数据库中与非洲相关的每个国家/地区:
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
谢谢,
React 上下文需要一个数据提供者和一个消费者。
假设您阅读了 the docs about context API 和其他一些来源。我将尝试弥补我第一次使用上下文时遗漏的部分。
- 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>
如果您只有一个消费者,您可能不需要上下文,您必须在正确的位置找到您的状态。
在多个项目中使用 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
将这些注释投射到您的需求中,我建议:
- 制作一个
ContinentProvider
来包装所有消费者并向他们提供国家/地区。
- 上下文可能包含多个大陆的数据,消费者可以选择他需要的。
- 上下文只保存值,它可以更智能并提供一个 fetchContinentData(continentName) 函数,如果缓存数据中不存在大陆国家,它将按需获取大陆国家
- 您可以制作一个直接提供大陆国家的挂钩:
useContinentCountries
使用 useContinentProvider
这里是 a codesandbox demo,看起来像这样:
有一个库实际上可以更轻松地使用多个上下文 https://www.npmjs.com/package/react-dynamic-context-provider。
编辑:使用钩子解决
我一直在疯狂地做这件事。我有一个问题,我必须在另一个组件中使用道具。我知道我应该使用上下文。
我遵循了一些教程,但由于某些原因,我无法将其应用到我自己的代码中。
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"]}
/>
我觉得我已经翻遍了所有的石头,但我想不出一个解决办法。 我清理了失败的尝试以使代码更具可读性。
编辑: 更新代码: 获取大陆:
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: 所以,如果我访问我的组件 "Africa": https://imgur.com/4LSPwS6 我想从我的数据库中加载每个国家/地区 "Africa"
当我单击 "Africa" 时,我想查看当前数据库中与非洲相关的每个国家/地区: 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
谢谢,
React 上下文需要一个数据提供者和一个消费者。
假设您阅读了 the docs about context API 和其他一些来源。我将尝试弥补我第一次使用上下文时遗漏的部分。
- 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>
如果您只有一个消费者,您可能不需要上下文,您必须在正确的位置找到您的状态。
在多个项目中使用 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
将这些注释投射到您的需求中,我建议:
- 制作一个
ContinentProvider
来包装所有消费者并向他们提供国家/地区。 - 上下文可能包含多个大陆的数据,消费者可以选择他需要的。
- 上下文只保存值,它可以更智能并提供一个 fetchContinentData(continentName) 函数,如果缓存数据中不存在大陆国家,它将按需获取大陆国家
- 您可以制作一个直接提供大陆国家的挂钩:
useContinentCountries
使用useContinentProvider
这里是 a codesandbox demo,看起来像这样:
有一个库实际上可以更轻松地使用多个上下文 https://www.npmjs.com/package/react-dynamic-context-provider。