context可以理解为一种全局的上下文变量。通过context我们可以跨级组件通信时不用在每一个组件使用props来传递值,直接在组件树之间来传递值和方法。只要是提供context组件的子组件都可以访问到context上的值。
Props
context
提供context的组件可以理解为生产者(provider),使用context的组件可以理解为消费者(consumer)。生产者通常为一个顶层的父组件,消费者通常为子组件。
1、context
Legacy Context
生产者
生产者(父组件)需要使用childContextTypes来定义提供的context的值,然后再使用getChildContext给定义的context赋值,需要注意的是childContextTypes和getChildContext必须同时一起使用:
import React from 'react'
import PropTypes form 'prop-types'
import Middle from './middle'
class Father extends React.Component {
// 给定义context赋值
getChildContext() {
return {
name: 'cauth',
age:18.
work: () => 'coding'
}
}
render() {
return (
<h1>Fathter component</h1>
<Middle />
)
}
}
// 1、定义context提供的值
Father.childContextTypes = {
name: PropTypes.string,
age: PropTypes.number,
work: PropTypes.func
}
Middle代码
import React from 'react'
import Child from './child'
class Middle extends React.Component {
render() {
return (
<Child />
)
}
}
export default Middle
消费者
消费者首先需要使用contextTypes声明需要的context,如果没有声明获取到的值时undefined;然后再从context中获取到所需要的值。
import React from 'react'
import PropTypes from 'prop-types'
class Child extends React.Component {
render() {
const { name, age, work } = this.context // 获取context的值
return (
<div>
<p>My name is { name } and { age } years old</p>
<button onClick={() => {alert(work())}}>点击调用父组件传递的方法</button>
</div>
)
}
}
// 定义子组件需要使用的context
Child.contextTypes = {
name: PropTypes.string,
age: PropTypes.number,
work: PropTypes.func
}
export default Child
使用context有以下四个关键的地方
childContextTypes,在生产者中定义提供的contextgetChildContext,在生产者中给定义的context赋值contextTypes,在消费者中定义需要的context(如果不定义会报错)const { xx, xx } = this.context,从context中获取值
除了从
this.context获取context还能从哪里获取呢?🤔
constructor(props, context)componentWillReceiveProps(nextProps, nextContext)shouldComponentUpdate(nextProps, nextState, nextContext)componentWillUpdate(nextProps, nextState, nextContext)
但是需要注意的是如果使用LegacyContext在消费者中使用了PureComponent,如果生产者对context进行改变,消费者不会发生新的render。
createContext
React.createContext,在为使用context时提供了一种全新API,更加贴切我们的使用习惯。使用createContext会创建一个provider以及consumer,这样的语法更加类似与生产者消费者模式。
生产者
首先在生产者中使用createContext创建一个context,然后使用context上的provider方法给子组件提供相应的context值。
import React from 'react'
import Child from './child'
export const GlobalContext = React.createContext({'name': 'who?', age: 0})
class Father extends React.Component {
render() {
return (
<div>
// 使用value来定义context提供的值
<GlobalContext.provider value={{name: 'cauth', age: 18}}>
<Child />
</GlobalContext>
</div>
)
}
}
消费者
消费者首先要获取到全局的context然后调用其consumer方法,需要注意的是consumer的child必须是一个函数。
import React from 'react'
import { FatherContext } from './father'
class Child extends React.Component {
render() {
return (
<FatherContext.Consumer>
{
context => { // context表示provider中value提供的值
const {name, age} = context
return (
<div>
{name}---{age}
</div>
)
}
}
</FatherContext.Consumer>
)
}
}
export default Child
context缺点
- 用于在组件使用了
context,代码耦合度较高,不利于组件复用。 context相当于一个全局变量,在使用的不能方便的追踪到数据源。