Context提供了一个无需为每层组件手动添加props,就能在组件树间进行数据传递的方法。 Context设计目的是为了共享那些对于一个组件树而言是"全局"的状态,例如当前认证的用户,主题或者首选语言。
Api
-
createContext
//context.js import {createContext} from 'createContext' const {Provider,Consumer} = createContext(initialValue)创建一个Context对象,initialValue为设置共享的默认数据
-
Provider
import {Provider} from '***/context.js' //组件中引入Provider function App(){ //// return ( <Provider value={/* 某个值or 对象 */}> <div> //伪代码 <Child /> </div> </Provider> ) }每个Context对象都返回一个Provider组件,它允许消费组件订阅context的变化,它接收一个value属性,传递给消费组件,当value发生变化时候,会跳过其子组件的shouldComponentUpdate函数传递给子组件内部的消费组件(Consumer)
-
contextType
import React , {Componnet} from 'react' import MyContext from '***/context.js' class Child extends Component { static contextType = myContext render(){ const val = this.context return ( <div>{val}</div> ) } } deport default Child消费组件使用contextType接收数据,当从离该组件最近的祖先组件的Provider传递过来的值发生变化时,重新渲染消费组件
-
Consumer
import React from 'react' import {Consumer} from '***/context.js' function Child(){ return ( <Cousumer> { val => { return ( <div>{val}</div> ) } } </Cousumer> ) }使用Consumer也可以订阅到context变更,但是需要在Consumer中return一个react节点,val为离这个组件最近的祖先组件的Provider提供的value值,如果没有,则为默认的initialValue
-
displayName
import MyContext from '***/context.js' MyContext.displayName = 'myDisplayName'在React DevTools中对显示的context对象的名称进行更改
使用场景
-
使用Provider和Consumer生产和消费数据
//context.js import {createContext} from 'react' export const {Provider,Consumer} = createContext('primary')父组件
import React, { useState } from "react"; import { Provider } from "./**/**/context"; import { Card, Select } from "antd"; import MidComponent from "./**/MidComponent"; const {Option} = Select function App(){ const [type, setType] = useState('') function handleTypeChange(val){ setType(val) //切换类型 } return ( <Provider value ={type}> <Card title = '更换按钮类型' style={{width:300}} className='card-box' extra = { <Select placeholder:'请选择一种类型' onChange={handleTypeChange} > <option value='primary'>primary</option> <option value='default'>default</option> <option value='link'>link</option> <option value='dashed'>dashed</option> <option value='text'>text</option> </Select> } > <MidComponent /> </Card> </Provider> ) }中间组件
import React, { Component } from "react"; import { Card } from "antd"; import { Consumer } from "./**/context"; import Child from "./**/Child "; class MidComponent extends Component { render() { return ( <Consumer> {(value) => ( <Card title={"你选择的类型是:" + value}> <Child /> </Card> )} </Consumer> ); } } export default MidComponent;//消费组件
import React, { Component } from "react"; import { Consumer } from "./**/context"; import { Button } from "antd"; class Child extends Component { render() { return ( <Consumer> {(type) => ( <div> 按钮 <Button type={type}>Button</Button> </div> )} </Consumer> ); } } export default Child结果显示:
-
Provider嵌套使用
//context.js import React ,{CreateContext} from 'react' export const {Provider,COnsumer} = createContext()组件中使用
import {Provider} from './**/context.js' function App(){ .... /// return ( <Provider value='primary' /> <div> <Mid /> //中间的组件 </div> <Provider> ) }//Mid.js import {Provider} from './**/context.js' function Mid(){ ... //// return ( <Provider value ='link'> // 里层的会覆盖外层的数据 <div> <Child /> </div> </Provider> ) }//Child.js import {COnsumer} from '/./**/context.js' function Child(){ return ( <Consumer> { value => <Button type={value}></Button> //link } </Consumer> ) } -
消费多个Context
//context.js import React, {createContext} from 'react' export const FirstContext = createContext() export const SecondContext = createContext()//订阅组件
import {FirstContext,SecondContext} from './context.js' //// /// /// return ( <FirstContext.Provider value={value1}> <SecondContext value={value2}> <Child /> </SecondContext> </FirstContext.Provider> )子组件
import {FirstContext,SecondContext} from './context.js' //// /// /// return ( <FirstContext.Consumer> { value1 => { <SecondContext.Consumer> { value2 => { .... ////// } } </SecondContext.Consumer> } } </FirstContext.Consumer> )
总结
- 创建context对象唯一方式是React.createContext(initialValue)
- 当React渲染了一个订阅这个Context对象的组件,这个组件会从最近父级的Provider中读取value值
- 当没有匹配到Provider时,initialValue才会生效
- Provider可以绕过其子组件中的shouldComponentUpdate函数来使得消费组件重新渲染
- 多个Provider可以嵌套
- contextType可以简化context使用,不使用Consumer也可以共享变量
- contextType和Consumer功能相似,但是contextType只能在类组件中使用
- contextType只能订阅单一context对象,可以使用this.context来消费最近的Context上的那个值