写在前面:本文适合有一定react基础的小伙伴,一些基础性的描述这里就不写了,官网也有,本文就是提炼一些主要内容,帮助你更好使用。有不同意见的记得评论区留下你的足迹哦,大家一起学习进步吧!
一、何时使用Context?
官网:Context 设计目的是为了共享那些对于一个组件树而言是“全局”的数据。
我:有数据被好几个组件都共用,但是不想从父组件一级一级通过props往下
传。如果组件嵌套太多层,还可能传错了,hhh。
二、使用Context前的考虑?
由于每个组件都可以通过单独的context方式去获取数据,而不是从外部传入通过props接收,这会导致组件的复用性变差。
三、如何使用Context?
1)创建一个context对象;
2)提供一个跨层级传递的数据 Provider(提供者);
3)在受用组件中使用一个接受对象 Consumer(消费者)。
还是通过具体代码示例来了解一下吧,真•具体•代码 如下:
第一步:创建一个父组件Home.jsx和一个子组件Son.jsx
import React, { Component } from 'react';
import Son from './Son'
export class Home extends Component {
state={
color:'red',
size:30
}
render() {
const {color,size}=this.state;
const valueProps={
size,color
}
return (
<div>
<p>Home </p>
<Son {...valueProps}/> //常规传递参数的方式
</div>
)
}
}
export default Home
import React, { Component } from 'react'
export class Son extends Component {
render() {
const {color,size}=this.props; //常规接收参数的方式
return (
<div >
<p style={{color:color,fontSize:size}}>Son</p>
</div>
)
}
}
export default Son
第二步:创建Context对象。(方便理解,我们把Context对象和返回的Provider React组件放到一个单独的context.js文件中)
import React from 'react';
export const DataContext=React.createContext();
export const DataProvider=DataContext.Provider;
export const DataConsumer=DataContext.Consumer;
所有的子组件需要包裹在provider中,并且接收一个value属性,即需要传递的数据。
第三步:改造父、子组件。
import React, { Component } from 'react';
import {DataProvider} from '../../utils/context';
import Son from './Son'
export class Home extends Component {
state={
color:'red',
size:3
}
render() {
const {color,size}=this.state;
const valueProps={
size,color
}
return (
<div className='margin fontSize'>
<p>home</p>
<DataProvider value={valueProps}>
<Son/>
//还有其他子组件 都放在这里
</DataProvider>
</div>
)
}
}
export default Home
// Son.jsx组件:
import React, { Component } from 'react'
import {ThemeContext} from './context';
export class Son extends Component {
// static contextType=ThemeContext;
render() {
const {color}=this.context;
return (
<div style={{color:color}}>
Son
</div>
)
}
}
Son.contextType=ThemeContext
export default Son
注意:挂载在组件上的contextType会被重赋值为一个Context对象,规定用this.context来访问那个值,可以在任何生命周期中使用它。
四、其他
1、如果子组件是个函数组件,写法是怎样呢?
让我们创建一个新的组件,就叫UsePage.jsx吧
import React from 'react';
export default function UsePage (){
return <div>
usepage
</div>
}
作为子组件引入到Son.jsx中,此时Son.jsx组件变成这样:
import React, { Component } from 'react'
import {DataContext} from '../../utils/context';
import UsePage from './UsePage'
export class Son extends Component {
// 指定 contextType 读取当前的 theme context。
// React 会往上找到最近的 theme Provider,然后使用它的值。
// static contextType=DataContext; //写法一
render() {
const {color,size}=this.context;
return (
<div >
<p style={{color:color,fontSize:size}}>Son</p>
<UsePage /> //在这引入组件
</div>
)
}
}
Son.contextType=DataContext //写法二
export default Son
此时页面显示:
注意:函数式页面需要用到react中的useContext方法,接受一个context作为参数。
import React,{useContext} from 'react';
import {DataContext} from '../../utils/context'
export default function UsePage (){
const myCtx=useContext(DataContext)
const {color,size}=myCtx;
return <div style={{color:color,fontSize:size}}>
usepage
</div>
}
页面显示:
2、还可以在创建Context对象时候给个默认值。
import React from 'react';
export const DataContext=React.createContext({
color:'green',
size:14
});
export const DataProvider=DataContext.Provider;
此时,包裹在provider中的组件会接收父组件新传入的数据,
外层组件就会拿到默认值了。
import React, { Component } from 'react';
import {DataProvider} from '../../utils/context';
import Son from './Son'
import UsePage from './UsePage'
import './home.scss'
export class Home extends Component {
state={
color:'red',
size:30
}
render() {
const {color,size}=this.state;
const valueProps={
size,color
}
return (
<div className='margin fontSize'>
<p>home</p>
<DataProvider value={valueProps}>
<Son/>
</DataProvider>
<UsePage />
</div>
)
}
}
export default Home
3、使用多个Context
让我们再来给文字添加一个背景颜色。同样,创建一个新的Context对象。
export const BackContext=React.createContext({
background:'yellow'
});
export const BackProvider=BackContext.Provider;
export const BackConsumer=BackContext.Consumer;
// Homes.jsx文件:
import React, { Component } from 'react';
import { DataProvider, BackProvider } from '../../utils/context';
import Son from './Son'
export class Home extends Component {
state = {
color: 'red',
size: 30,
background:'orange'
}
render() {
const { color, size ,background} = this.state;
const valueProps = {
size, color
}
return (
<div>
<p>home</p>
<BackProvider value={background}>
<DataProvider value={valueProps}>
<Son />
</DataProvider>
</BackProvider>
</div>
)
}
}
export default Home
// Son.jsx:
import React, { Component } from 'react'
import { BackConsumer, DataConsumer } from '../../utils/context';
export class Son extends Component {
render() {
return (
<BackConsumer>
{
background=> (
<DataConsumer>
{
({color,size}) => {
return <p style={{ color: color, fontSize: size,backgroundColor:background }}>Son</p>
}
}
</DataConsumer>
)
}
</BackConsumer>
)
}
}
export default Son
usepage没有接受上级组件传递的color和size,使用了给的默认值
总结:
ContextType写法(static contextType=DataContext):
1、只能用在类组件中;
2、只能订阅单一的数据来源(如果需要多个,就使用Consumer);
useContext()写法(const ctx = React.useContext(ThemeContext)):
1、只能用在函数组件中;
2、可以订阅多个context对象
Consumer可以用在类组件和函数组件中,但是写法有点复杂了,多个需要一直嵌套下去。
消耗的性能很大,因为状态值存在父组件的state中,一旦更新一个数据,所有子组件都会更新。
所以现在可能redux用的比较多了(我自己是这样没错啦)。
有不足之处希望大家踊跃发言,接受一切批评、建议,为了美好的明天,冲!