React?Context用法小結(jié)(附完整代碼)
前言
傳統(tǒng)的React應(yīng)用中,數(shù)據(jù)通過props屬性自上而下(由父組件向子組件)傳遞,當(dāng)組件層級數(shù)量增多時,在每一層傳遞props則很繁瑣,Context提供了一種新的組件之間共享數(shù)據(jù)的方式,允許數(shù)據(jù)隔代傳遞,而不必顯式的通過組件樹逐層傳遞props。
根據(jù)官網(wǎng)鏈接對Context常用的5種使用場景進行了整理,并隨文配上完整代碼。
使用場景:
- 父組件使用Provider生產(chǎn)數(shù)據(jù),子組件使用Consumer消費數(shù)據(jù)
- 子組件使用ContextType接收數(shù)據(jù)
- 動態(tài)和靜態(tài)Context(父組件更新Context,被Provider包裹的子組件刷新數(shù)據(jù),沒被Provider包裹的子組件使用Context默認(rèn)值)
- 在嵌套組件中更新Context(子組件通過Context傳遞的函數(shù)更新數(shù)據(jù))
- 消費多個Context
知識點匯總
- 首先創(chuàng)建1個Context對象,當(dāng)React渲染1個訂閱了Context對象的組件,這個組件會從組件樹中離自身最近的那個匹配的Provider讀取到當(dāng)前的context值。
- 每個Context都返回1個React組件,允許消費組件訂閱context的變化
- ContextType只能在類組件中使用
- 1個組件如果有多個消費者,ContextType支隊其中1個有效,也就是ContextType只能有1個(所以推薦使用Provider和Consumer形式)
場景1:使用Provider和Consumer生產(chǎn)和消費數(shù)據(jù) 文件目錄及說明
以下文件在同級路徑:
- ProductContext.js:創(chuàng)建的Context組件文件
- ProviderPage.js:父組件(數(shù)據(jù)生產(chǎn)者)
- MiddlePage.js:中間組件
- ConsumerPage.js:子組件(數(shù)據(jù)消費者)
數(shù)據(jù)傳遞路徑:
ProviderPage.js ==> MiddlePage.js ==> ConsumerPage.js
代碼文件 ProductContext.js:
import React from 'react';
// Context 可以讓我們無須明確地傳遍每一個組件,就能將值深入傳遞進組件樹。
// 創(chuàng)建1個Context對象并給定默認(rèn)值,如果沒有匹配到Provider,消費組件取Context默認(rèn)值
export const ProductContext = React.createContext({
name: 'car',
price: 8000,
unit: '$',
});
export const { Provider, Consumer } = ProductContext;ProviderPage.js:
import React, { PureComponent } from 'react';
import MiddlePage from './MiddlePage';
import { Provider } from './ProductContext';
class ProviderPage extends PureComponent {
state = {
product: {
name: 'plane',
price: 120000,
unit: '$',
},
};
render() {
const { product } = this.state;
return (
<div>
<h1>根組件使用Provider傳值,子組件使用Consumer接收</h1>
<Provider value={product}>
<MiddlePage />
</Provider>
{/*不用Provider,顯示Context對象defaultValue*/}
{/* <MiddlePage />*/}
</div>
);
}
}
export default ProviderPage;
MiddlePage.js:
import React, { PureComponent } from 'react';
import ConsumerPage from './ConsumerPage';
class MiddlePage extends PureComponent {
render() {
return (
<ConsumerPage />
);
}
}
export default MiddlePage;ConsumerPage.js:
import React, { PureComponent } from 'react';
import { Consumer } from './ProductContext';
class ConsumerPage extends PureComponent {
render() {
return (
<Consumer>
{context => {
return (
<div>
name:{context.name}
<br />
price:{context.price}
<br />
unit:{context.unit}
</div>
);
}}
</Consumer>
);
}
}
export default ConsumerPage;效果

可以看到顯示的是ProviderPage組件提供的Context值。
場景2:使用ContextType接收數(shù)據(jù)
文件目錄及說明
- FamilyContext.js:創(chuàng)建的Context組件
- FatherPage.js:父組件(生產(chǎn)數(shù)據(jù))
- SonPage.js:子組件(中間組件)
- GrandSonPage.js:孫組件(消費數(shù)據(jù))
代碼文件
FamilyContext.js
import React, { PureComponent } from 'react';
import SonPage from './SonPage';
import { Provider } from './FamilyContext';
class FatherPage extends PureComponent {
state = {
person: {
name: 'Lora',
age: 99,
gender: 'female',
},
};
render() {
const { person } = this.state;
return (
<div>
<h1>使用ContextType消費Context數(shù)據(jù)</h1>
<Provider value={person}>
<SonPage />
</Provider>
{/*不用Provider,顯示Context對象defaultValue*/}
{/*<SonPage />*/}
</div>
);
}
}
export default FatherPage;
SonPage.js:和上面的MiddlePage.js一樣
import React, { PureComponent } from 'react';
import GrandSonPage from './GrandSonPage'
class SonPage extends PureComponent {
render() {
return (
<GrandSonPage />
);
}
}
export default SonPage;GrandSonPage.js:使用ContextType接收數(shù)據(jù)
import React, { PureComponent } from 'react';
import { FamilyContext } from './FamilyContext';
class GrandSonPage extends PureComponent {
//
static contextType = FamilyContext;
componentDidMount() {
// 使用contexType可以在任意生命周期訪問數(shù)據(jù)
// 使用 this.context 來消費最近 Context 上的那個值
const value = this.context;
console.log(value);
}
render() {
// Context是1個對象,對對象進行解構(gòu)操作
const { name, age, gender } = this.context;
return (
<div>
name:{name}
<br />
age:{age}
<br />
gender:{gender}
</div>
);
}
}
export default GrandSonPage;
效果

場景3:動態(tài)和靜態(tài)Context
在ProviderPage.js中,被Provider包裹的組件可以更新的Context數(shù)據(jù),沒被Provider包裹的組件只能獲取Context默認(rèn)值。
代碼文件
ProductContext.js
import React from 'react';
// Context 可以讓我們無須明確地傳遍每一個組件,就能將值深入傳遞進組件樹。
// 創(chuàng)建1個Context對象
// 默認(rèn)值,如果沒有匹配到Provider取默認(rèn)值
export const ProductContext = React.createContext({
name: 'car',
price: 17000,
unit: '$',
});
export const { Provider, Consumer } = ProductContext;ProviderPage.js
import React, { PureComponent } from 'react';
import { Button, Divider } from 'antd';
import MiddlePage from './MiddlePage';
import { Provider } from './ProductContext';
class ProviderPage extends PureComponent {
state = {
product: {
name: 'plane',
price: 120000,
unit: '$',
},
};
handleChange = () => {
const { product: { name, price, unit } } = this.state;
this.setState({
product: {
name,
price: price + 1,
unit,
},
});
};
render() {
const { product } = this.state;
return (
<div>
<h1>父組件更新Context,被Provider包裹的子組件刷新值,沒被包裹的子組件使用Context默認(rèn)值</h1>
{/*在Provider包裹的內(nèi)部組件使用state中的值*/}
<Provider value={product}>
<MiddlePage />
</Provider>
<Divider />
{/*不在Provider包裹的外部組件使用ProductContext重的默認(rèn)值*/}
<MiddlePage />
<Divider />
<Button
onClick={this.handleChange}
type="primary"
>
增加
</Button>
</div>
// {不用Provider,顯示Context對象defaultValue
// <MiddlePage />
);
}
}
export default ProviderPage;
MiddlePage.js
import React, { PureComponent } from 'react';
import ConsumerPage from './ConsumerPage';
class MiddlePage extends PureComponent {
render() {
return (
<ConsumerPage />
);
}
}
export default MiddlePage;ConsumerPage.js
import React, { PureComponent } from 'react';
import { Consumer } from './ProductContext';
class ConsumerPage extends PureComponent {
render() {
return (
<Consumer>
{context => {
return (
<div>
name:{context.name}
<br />
price:{context.price}
<br />
unit:{context.unit}
</div>
);
}}
</Consumer>
);
}
}
export default ConsumerPage;效果

點擊增加按鈕,上面的price會增加(使用Context更新值),下面的不變(使用Context默認(rèn)值)。
場景4:在嵌套組件中更新Context
代碼文件
ProductContext.js
import React from 'react';
// Context 可以讓我們無須明確地傳遍每一個組件,就能將值深入傳遞進組件樹。
// 創(chuàng)建1個Context對象
// 注意第1個參數(shù)是1個object {}
export const ProductContext = React.createContext({
product: {
name: 'car',
price: 8000,
unit: '$',
},
// 通過context傳遞1個函數(shù),使得consumer組件更新context
handlePrice: () => {
},
},
);
export const { Provider, Consumer } = ProductContext;ProviderPage.js
import React, { PureComponent } from 'react';
import MiddlePage from './MiddlePage';
import { Provider } from './ProductContext';
class ProviderPage extends PureComponent {
state = {
product: {
name: 'plane',
price: 120000,
unit: '$',
},
// state頁包含了更新函數(shù),因此會被傳遞進context provider
handlePrice: () => this.handlePrice(),
};
handlePrice = () => {
const { product: { name, price, unit } } = this.state;
this.setState({
product: {
name,
price: price + 1,
unit,
},
});
};
render() {
const { product, handlePrice } = this.state;
return (
<div>
<h1>子組件通過context傳遞的函數(shù)更新context,等于在子組件中更新狀態(tài)</h1>
{/*注意此時傳遞進去的是state,包含product對象和1個函數(shù)*/}
<Provider value={{ product, handlePrice }}>
<MiddlePage />
</Provider>
{/*不用Provider,顯示Context對象defaultValue*/}
{/* <MiddlePage />*/}
</div>
);
}
}
export default ProviderPage;
MiddlePage.js
import React, { PureComponent } from 'react';
import ConsumerPage from './ConsumerPage';
class MiddlePage extends PureComponent {
render() {
return (
<ConsumerPage />
);
}
}
export default MiddlePage;ConsumerPage.js
import React, { PureComponent } from 'react';
import { Button, Divider } from 'antd';
import { Consumer } from './ProductContext';
class ConsumerPage extends PureComponent {
render() {
return (
<Consumer>
{/*創(chuàng)建的Context對象*/}
{/*ConsumerPage組件不僅從context獲取product對象值,還獲取1個handlePrice函數(shù)*/}
{/*注意參數(shù)名要和Provider中傳入的以及context中定義的一摸一樣*/}
{context => {
return (
<div>
name:{context.product.name}
<br />
price:{context.product.price}
<br />
unit:{context.product.unit}
<Divider />
<Button
onClick={context.handlePrice}
type="primary"
>
增加
</Button>
</div>
);
}}
</Consumer>
);
}
}
export default ConsumerPage;
效果

增加按鈕在子組件ConsumerPage.js中定義,Context傳遞1個函數(shù)給子組件,具體的函數(shù)實現(xiàn)在父組件ProviderPage.js中,此處感覺還是類似React回調(diào)函數(shù),優(yōu)勢就是中間組件MiddlePage不用傳遞任何props,包括回調(diào)函數(shù)。
場景5:消費多個Context
代碼文件
MultiContext.js
import React from 'react';
const SchoolContext = React.createContext({
name: '南師附中',
location: '南京',
});
const StudentContext = React.createContext({
name: 'chengzhu',
age: 17,
});
export { SchoolContext, StudentContext };ProviderPage.js
import React, { PureComponent } from 'react';
import MiddlePage from './MiddlePage';
import { SchoolContext, StudentContext } from './MultiContext';
class ProviderPage extends PureComponent {
state = {
school: {
name: '清華大學(xué)',
location: '北京',
},
student: {
name: '張云',
age: 22,
},
};
render() {
const { school, student } = this.state;
return (
<div>
<h1>消費多個Context</h1>
<SchoolContext.Provider value={school}>
<StudentContext.Provider value={student}>
<MiddlePage />
</StudentContext.Provider>
</SchoolContext.Provider>
</div>
// 不用Provider包裹顯示Context中定義的默認(rèn)值
// <MiddlePage />
);
}
}
export default ProviderPage;
MiddlePage.js
import React, { PureComponent } from 'react';
import ConsumerPage from './ConsumerPage';
class MiddlePage extends PureComponent {
render() {
return (
<ConsumerPage />
);
}
}
export default MiddlePage;ConsumerPage.js
import React, { PureComponent } from 'react';
import { SchoolContext, StudentContext } from './MultiContext';
class ConsumerPage extends PureComponent {
render() {
return (
<SchoolContext.Consumer>
{school => (
<StudentContext.Consumer>
{student => {
return (
<div>
就讀學(xué)校: {school.name}
<br />
學(xué)校位置: {school.location}
<br />
學(xué)生姓名: {student.name}
<br />
學(xué)生年齡: {student.age}
</div>
);
}}
</StudentContext.Consumer>
)}
</SchoolContext.Consumer>
);
}
}
export default ConsumerPage;效果

可以看到傳遞了2個Context,分別是SchoolContext和StudentContext,子組件ConsumerPage消費了傳遞進來的2個Context數(shù)據(jù)。
到此這篇關(guān)于React Context用法小結(jié)(附完整代碼)的文章就介紹到這了,更多相關(guān)React Context用法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
React+Spring實現(xiàn)跨域問題的完美解決方法
這篇文章主要介紹了React+Spring實現(xiàn)跨域問題的完美解決方法,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下2018-08-08
React、Vue中key的作用詳解 (key的內(nèi)部原理解析)
key是虛擬DOM對象的標(biāo)識,當(dāng)狀態(tài)中的數(shù)據(jù)發(fā)生變化時,Vue會根據(jù)[新數(shù)據(jù)]生成[新的虛擬DOM],本文給大家介紹React、Vue中key的作用詳解 (key的內(nèi)部原理解析),感興趣的朋友一起看看吧2023-10-10
Webpack 4.x搭建react開發(fā)環(huán)境的方法步驟
這篇文章主要介紹了Webpack 4.x搭建react開發(fā)環(huán)境的方法步驟,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-08-08
React router動態(tài)加載組件之適配器模式的應(yīng)用詳解
這篇文章主要介紹了React router動態(tài)加載組件之適配器模式的應(yīng)用 ,本文通過實例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下2018-09-09

