应用场景
- 当你需要在整个组件树传递数据,但是不想手动的在每一层传递属性时。
- Props提供的是在上下级组件(自上而下一级一级)的数据传递
- Context提供了在组件之间的数据传递(不需要一级一级传递)
应用案例
改变指定组件的边框颜色
旧版context的用法
-
导入 prop-types包
import PropTypes from 'prop-types' -
在父组件中先定义子上下文的属性和方法的类型,然后再去实现子上下文
static childContextTypes = { color:PropTypes.string, setColor:PropTypes.func } getChildContext(){ return { color:this.state.color, setColor:this.setColor } } -
在子孙组件的获取需要的上下文属性,可以全部获取,可以部分获取
static contextTypes{ color: PropTypes.string, setColor:PropTypes.func } -
代码实现:
import React from 'react' import PropTypes from 'prop-types' class Title extends React.Component { constructor(props) { super(props) } static contextTypes = { color: PropTypes.string } render() { let style = { border: '5px solid ' + this.context.color, padding: '10px' } return <div style={style}>Title</div> } } class Header extends React.Component { constructor(props) { super(props) } static contextTypes = { color: PropTypes.string } render() { let style = { border: '5px solid ' + this.context.color, padding: '10px' } return ( <div style={style}> Header <Title /> </div> ) } } export default class Page extends React.Component { constructor(props) { super(props) this.state = { color: 'red' } } // 定义子上下文的属性和方法类型 static childContextTypes = { color: PropTypes.string, setColor: PropTypes.func } // 实现子上下文 getChildContext() { return { color: this.state.color, setColor: this.setColor } } setColor = (color) => { this.setState({ color }) } render() { let style = { border: '5px solid ' + this.state.color, padding: '10px', height: '270px', width: '200px' } return ( <div style={style}> page <Header /> <Main /> </div> ) } } class Content extends React.Component { constructor(props) { super(props) } static contextTypes = { color: PropTypes.string, setColor: PropTypes.func } render() { let style = { border: '5px solid ' + this.context.color, padding: '10px' } return ( <div style={style}> Content <br /> <button onClick={() => this.context.setColor('red')} style={{ marginRight: '5px' }} > 红色 </button> <button onClick={() => this.context.setColor('green')}> 绿色 </button> </div> ) } } class Main extends React.Component { constructor(props) { super(props) } static contextTypes = { color: PropTypes.string } render() { let style = { border: '5px solid ' + this.context.color, padding: '10px', marginTop: '20px' } return ( <div style={style}> Main <Content /> </div> ) } } -
实现效果

新版context的用法
- 全局创建一个上下文
let ThemeContext = React.createContext()
- 在父组件中 render的返回值中 使用 ThemeContext.Provider 将value 传递给子孙组件,属性value(这个名称是固定的)
return (
<ThemeContex.Provider value={需要传递的对象或者值}>
原组件内容
</ThemeContex.Provider>
)
-
在子组件中的使用
-
类组件
定义一个contextType就可以通过this.context 获取到父组件传递过来的对象或者值
static contextType = ThemeContext -
函数组件
使用ThemeContext.Consumer 获取到父组件传递过来的对象或者值
return ( <ThemeContext.Consumer> { (context)=>{ <div style={{ border: '5px solid ' + context.color, padding: '10px' }} > Title Function </div> } } </ThemeContext.Consumer> )
-
-
代码实现:
import React from 'react'
import PropTypes from 'prop-types'
let ThemeContext = React.createContext()
/* class Title extends React.Component {
static contextType = ThemeContext
render() {
let style = {
border: '5px solid ' + this.context.color,
padding: '10px'
}
return <div style={style}>Title</div>
}
} */
function Title() {
return (
<ThemeContext.Consumer>
{(context) => (
<div
style={{
border: '5px solid ' + context.color,
padding: '10px'
}}
>
Title Function
</div>
)}
</ThemeContext.Consumer>
)
}
class Header extends React.Component {
static contextType = ThemeContext
render() {
let style = {
border: '5px solid ' + this.context.color,
padding: '10px'
}
return (
<div style={style}>
Header
<Title />
</div>
)
}
}
export default class Page extends React.Component {
state = {
color: 'red'
}
setColor = (color) => {
this.setState({
color
})
}
render() {
let style = {
border: '5px solid ' + this.state.color,
padding: '10px',
height: '270px',
width: '200px'
}
return (
<ThemeContext.Provider
value={{ color: this.state.color, setColor: this.setColor }}
>
<div style={style}>
page
<Header />
<Main />
</div>
</ThemeContext.Provider>
)
}
}
class Content extends React.Component {
static contextType = ThemeContext
render() {
let style = {
border: '5px solid ' + this.context.color,
padding: '10px'
}
return (
<div style={style}>
Content
<br />
<button
onClick={() => this.context.setColor('red')}
style={{ marginRight: '5px' }}
>
红色
</button>
<button onClick={() => this.context.setColor('green')}>
绿色
</button>
</div>
)
}
}
class Main extends React.Component {
static contextType = ThemeContext
render() {
let style = {
border: '5px solid ' + this.context.color,
padding: '10px',
marginTop: '20px'
}
return (
<div style={style}>
Main
<Content />
</div>
)
}
}
- 效果图(同旧版一致)

简单实现 新版context
分析新版context
-
React.createReact() 是一个无入参的函数,返回值为一个对象,{Provider,Consumer}
-
Provider
- 提供者,父组件通过它将数据传递给子孙组件
- 它是一个类组件,没有自己的react元素,渲染的是子组件,接收一个value(固定名称)的props属性, 这个属性是一个静态属性,可以通过组件获取,
class Provider extends React.Component{ static value constructor(props){ super(props) // 获取value赋值给静态属性 Provider.value = props.value } render(){ // 直接渲染子组件 return this.props.children } }- 在状态更新的时候,同时更新类组件的静态属性value的值
// 状态或者组件更新的时候,这个方法执行 static getDerivedStateFromProps(nextProps,preState){ // 更新value值 Provider.value = nextProps.value } -
Consumer
- 子孙组件(函数组件)可以通过它来获取父组件传递过来的数据
- 也是一个组件
- 直接渲染子组件,传入父组件传递过来的数据
render(){ return this.props.children(Provider.value) } -
注意事项
- 我们首先要定义一下两个变量,去欺骗react,将我们的context当成自己的
- 在类组件中获取父组件传递的数据时,通过当前组件的静态属性contextType找到其Provider的属性的value值
static contextType = ThemeContext this.context = Main.contextType.Provider.value -
代码实现
import React from 'react'
// 定义这两个常量是为了骗过react,将我们定义的context当成自己的
const REACT_CONTEXT_TYPE = Symbol.for('react.context')
const REACT_PROVIDER_TYPE = Symbol.for('react.provider')
let ThemeContext = createContext()
function createContext() {
class Provider extends React.Component {
$$typeof = REACT_PROVIDER_TYPE
static value
constructor(props) {
super(props)
Provider.value = props.value
}
static getDerivedStateFromProps(nextProps, preState) {
Provider.value = nextProps.value
}
render() {
return this.props.children
}
}
class Consumer extends React.Component {
render() {
return this.props.children(Provider.value)
}
}
return { $$typeof: REACT_CONTEXT_TYPE, Provider, Consumer }
}
/* class Title extends React.Component {
static contextType = ThemeContext
render() {
this.context = Title.contextType.Provider.value
let style = {
border: '5px solid ' + this.context.color,
padding: '10px'
}
return <div style={style}>Title</div>
}
} */
function Title() {
return (
<ThemeContext.Consumer>
{(context) => (
<div
style={{
border: '5px solid ' + context.color,
padding: '10px'
}}
>
Title Function
</div>
)}
</ThemeContext.Consumer>
)
}
class Header extends React.Component {
static contextType = ThemeContext
render() {
this.context = Header.contextType.Provider.value
let style = {
border: '5px solid ' + this.context.color,
padding: '10px'
}
return (
<div style={style}>
Header
<Title />
</div>
)
}
}
export default class Page extends React.Component {
state = {
color: 'red'
}
setColor = (color) => {
this.setState({
color
})
}
render() {
let style = {
border: '5px solid ' + this.state.color,
padding: '10px',
height: '270px',
width: '200px'
}
return (
<ThemeContext.Provider
value={{ color: this.state.color, setColor: this.setColor }}
>
<div style={style}>
page
<Header />
<Main />
</div>
</ThemeContext.Provider>
)
}
}
class Content extends React.Component {
static contextType = ThemeContext
render() {
this.context = Content.contextType.Provider.value
let style = {
border: '5px solid ' + this.context.color,
padding: '10px'
}
return (
<div style={style}>
Content
<br />
<button
onClick={() => this.context.setColor('red')}
style={{ marginRight: '5px' }}
>
红色
</button>
<button onClick={() => this.context.setColor('green')}>
绿色
</button>
</div>
)
}
}
class Main extends React.Component {
static contextType = ThemeContext
render() {
this.context = Main.contextType.Provider.value
let style = {
border: '5px solid ' + this.context.color,
padding: '10px',
marginTop: '20px'
}
return (
<div style={style}>
Main
<Content />
</div>
)
}
}
- 实现效果
