一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第27天,点击查看活动详情。
使用说明
我们使用context时的步骤为三步:
- 使用
React.createContext()
创建context对象 - 使用
provider
传递value - 子组件消费,有三种途径:
contextType
(类组件)、useConetxt
(函数组件方法)、<Context.Consumer>
标签(类组件函数组件通用)
【注意】使用多个context实例时需注意,Class.contextType
只能订阅单一context,多个会被覆盖。
step1. 创建context对象
Context说明: 创建一个 Context 对象。当 React 渲染一个订阅了这个 Context 对象的组件,这个组件会从组件树中离自身最近的那个匹配的 Provider
中读取到当前的 context 值。
创建Context对象: 创建context.js文件:
import React from 'react';
export const Context = React.createContext()
export const UserContext = React.createContext()
【注意】Context实例必须在单独文件中声明,不能声明在父组件文件中然后export,否则会在contextType(类组件)消费时报错:Uncaught ReferenceError: Cannot access 'UserListContext' before initialization
step2. 使用provider
传递value
Provider说明:
Provider 接收一个 value
属性,传递给消费组件,允许消费组件订阅 context 的变化。一个 Provider 可以和多个消费组件有对应关系。多个 Provider 也可以嵌套使用,里层的会覆盖外层的数据。
当 Provider 的 value
值发生变化时,它内部的所有消费组件都会重新渲染。Provider 及其内部 consumer 组件都不受制于 shouldComponentUpdate
函数,因此当 consumer 组件在其祖先组件退出更新的情况下也能更新。
Provider使用: 创建index.js
import React, { Component } from 'react';
import { Context, UserContext } from './context';
import Child from './child';
// 使用单一Context
// class MyContext extends Component {
// render() {
// return (
// <Context.Provider value={'red'}>
// 父组件
// <br />
// <Child />
// </Context.Provider>
// )
// }
// }
// 使用两个context
function MyContext() {
return(
<Context.Provider value={'red'}>
父组件2
<UserContext.Provider value={'小明'}>
使用两个context
<Child />
</UserContext.Provider>
</Context.Provider>
)
}
export default MyContext;
step3. 子组件消费:三种方式
1. 使用contextType
(类组件)
import React, { Component } from 'react';
// 需要使用同一个context
import { Context, UserContext } from './context';
class Child extends Component {
// 使用contextType消费,传入的值会自动挂在this.context中
static contextType = Context
// 无法使用contextType分别消费两个Context实例,this.context的值会被覆盖
// static contextType = UserContext
render() {
console.log(this.context)
return (
<div style={{color: this.context}}>
使用contextType消费:取到的context值 {this.context}
</div>)
}
}
export default Child;
Class.contextType
只能订阅单一context,多个会被覆盖。
2. 使用useConetxt
(函数组件方法)
import React, { useContext } from 'react';
import { Context, UserContext } from './context';
function Child() {
const val = useContext(Context)
// 可以使用useContext分别来消费两个context实例
const name = useContext(UserContext)
return(
<div style={{color: val}}>
使用useContext消费:取到的context值 {val}<br/>
{/* 第二个context值 {name} */}
</div>)
}
export default Child;
3. 使用<Context.Consumer>
标签(类组件函数组件通用)
使用语法:<Context.Consumer>
标签中间接收一个回调函数,回调函数的参数就是这个context实例传递的值,然后其回调函数return的jsx
中就可以使用传进来的值了。
<Context.Consumer>{ (value)=> <div> {value} </div> }</Context.Consumer>
import React, { Component, useContext } from 'react';
import { Context, UserContext } from './context';
class Child extends Component {
render() {
return(
<div>
<Context.Consumer>
{ (color)=> <div style={{color}}>Context.Consumer-class组件取值:{ color }</div> }
</Context.Consumer>
{/* <UserContext.Consumer>
{ (name)=> <div>第二个context值:{ name }</div> }
</UserContext.Consumer> */}
</div>)
}
}
// 函数组件使用Context.Consumer
// function Child() {
// return(<>
// <Context.Consumer>
// { (color)=> <div style={{color}}>Context.Consumer-函数组件取值:{ color }</div> }
// </Context.Consumer>
// {/* <UserContext.Consumer>
// { (name)=> <div>第二个context值:{ name }</div> }
// </UserContext.Consumer> */}
// </>)
// }
export default Child;
使用context总结及注意事项
- 使用
React.createContext()
创建context,并在父组件中使用<Context.Provider value={xx}>
传值。【注】最好将声明对象的步骤放在单独文件中,否则在class组件消费时会报错。 - 消费的三种方法:
contextType
方法只受限于类组件,且不能使用多层的context嵌套传值,只可订阅单一context对象;useConetxt
方法需要使用在函数组件或自定义hook,可以接收多层context的传值<Context.Consumer>
这种方法类组件和函数组件都可以通用,且不限制是否多层context传值,比较灵活,但其特点是写法比较麻烦,需要接收回调函数。