React-Context
类似广播功能
可以无视props进行值传递,多用于共用值:
例如:
import React from 'react';
const CommonUse = React.createContext(
"公用参数"
);
export default class UseContext extends React.Component{
constructor(props){
super(props);
}
render(){
return (
<div>
Context的使用
<CommonUse.Provider value="everyone to use">
<ContextChild />
<ContextChildTwo />
</CommonUse.Provider>
</div>
)
}
}
class ContextChild extends React.Component{
render(){
return (
<div>子组件 {this.context}</div>
)
}
}
ContextChild.contextType = CommonUse;
class ContextChildTwo extends React.Component{
render(){
return (
<CommonUse.Consumer>
{value => (
<div>
{this.context['name']}
<ContextChildTwoChild />
</div>
)}
</CommonUse.Consumer>
)
}
}
class ContextChildTwoChild extends React.Component{
static contextType = CommonUse;
render(){
return(
<div>我也在用 我是2的子组件 {this.context} </div>
)
}
}
定义完Context后需要将用此值的组件放在
<MyContext.Provider value="要传递的值"> </MyContext.Provider>
标签中。
注:使用this.context的时候必须经过contextType的挂载,官方提供三种方法,第三种方法可供函数组件使用:
//1. 将contextType挂载到类上:
class ContextChildTwo extends React.Component{
render(){
return (
<div>{this.context}</div>
)
}
}
ContextChildTwo.contextType = CommonUse;
//2.使用实验性语法static
class ContextChildTwo extends React.Component{
static contextType = CommonUse;
render(){
return (
<div>
{this.context}
</div>
)
}
}
//3.使用Context.Consumer(订阅context更新)
class ContextChildTwo extends React.Component{
render(){
return (
<CommonUse.Consumer>
{value => (
<div>
{this.context['name']}
</div>
)}
</CommonUse.Consumer>
)
}
}
如果要传递对象的时候要这么写,否则可能出现问题
import React from 'react';
const CommonUse = React.createContext(
"公用参数"
);
export default class UseContext extends React.Component{
constructor(props){
super(props);
// **********
this.state = {
contextValue :{
name : 'Oh'
}
}
}
render(){
return (
<div>
Context的使用
<CommonUse.Provider value={this.state.contextValue}>
<ContextChild />
</CommonUse.Provider>
</div>
)
}
}
class ContextChild extends React.Component{
render(){
return (
<div>子组件 {this.context['name']}</div>
)
}
}
ContextChild.contextType = CommonUse;
初始如果想将context默认值定义为对象则这么写:
const contextObj = {
name:"Tom"
}
const NameContext = React.createContext(contextObj);
动态修改context
const ActiveObjectValue = {
name:"Tom",
othername:"Jack"
}
const ActiveContext = React.createContext(ActiveObjectValue);
class Active extends React.Component{
constructor(props){
super(props);
this.changeName = ()=>{
this.setState(state=>({
name:state.name == ActiveObjectValue['name'] ? ActiveObjectValue['othername'] : ActiveObjectValue['name']
}))
}
this.state = {
name:"Jack"
}
}
render(){
return (
<ActiveContext.Provider value={this.state.name}>
<ActiveChild changeName={this.changeName}/>
</ActiveContext.Provider>
)
}
}
class ActiveChild extends React.Component{
render(){
return (
<div>
<button onClick={this.props.changeName}>{this.context}</button>
</div>
)
}
}
ActiveChild.contextType = ActiveContext;
在嵌套组件中更新Context
写一个例子,通过点击按钮改变姓名:
const NameObject = {
name : "Tom",
othername:"Jack"
}
const ContextObject = {
name:NameObject['name'],
changeName:()=>{}
}
const UseContextObject = React.createContext(ContextObject);
//父组件
class Parent extends React.Component{
constructor(props){
super(props);
this.changeName = ()=>{
this.setState(state=>({
name:state['name'] == NameObject['name'] ? NameObject['othername'] : NameObject['name']
}))
}
this.state = {
name:NameObject['name'],
changeName:this.changeName
}
}
render(){
return (
<div>
<UseContextObject.Provider value={this.state}>
<Content />
</UseContextObject.Provider>
</div>
)
}
}
//嵌套
class Content extends React.Component{
render(){
return (
<div><Child/></div>
)
}
}
//末端子组件
class Child extends React.Component{
render(){
return(
<UseContextObject.Consumer>
{
({name,changeName})=>(
<div>
<button onClick={changeName}>{name}</button>
</div>
)
}
</UseContextObject.Consumer>
)
}
}
首先为context定义初始值和修改姓名的方法
然后在在父组件构造函数中的state中定义姓名和更改姓名的方法,并将state全部传给最末端子组件的context
然后在子组件中使用.Consumer来实现点击切换姓名。(Consumer可以订阅context变更)
两个Context嵌套使用
使用Context.Consumer标签:
import React from 'react';
const CommonUse = React.createContext(
"公用参数"
);
const CommonUseTwo = React.createContext('default');
export default class UseContext extends React.Component{
constructor(props){
super(props);
this.state = {
contextValue :{
name : 'Oh'
}
}
}
render(){
return (
<div>
Context的使用
<CommonUseTwo.Provider value="嵌套使用">
<CommonUse.Provider value={this.state.contextValue}>
<ContextChild />
</CommonUse.Provider>
</CommonUseTwo.Provider>
</div>
)
}
}
class ContextChild extends React.Component{
render(){
return (
<div>
<CommonUse.Consumer>
{value =>(
<CommonUseTwo.Consumer>
{valueTwo => (
<div>双值嵌套 + {value['name']} + {valueTwo}</div>
)}
</CommonUseTwo.Consumer>
)}
</CommonUse.Consumer>
</div>
)
}
}
子组件中使用这种方式:
<CommonUse.Consumer>
{value =>(
<CommonUseTwo.Consumer>
{valueTwo => (
<div>双值嵌套 + {value['name']} + {valueTwo}</div>
)}
</CommonUseTwo.Consumer>
)}
</CommonUse.Consumer>
将所需的两个值分别嵌套,内层值在外层值的回调中使用。
组合组件减少props传值次数
比如这样一种情况的出现:
import React from 'react';
function Top(props){
return <Center/>
}
function Center(props){
return <CenterTwo/>
}
function CenterTwo(props){
return <Bottom/>
}
function Bottom(props){
return <div>{ props.name }{ prps.age }</div>
}
export default Top;
原先传递数据的方式:
import React from 'react';
function Top(props){
return <Center name="Tom" age="20"/>
}
function Center(props){
return <CenterTwo name={props.name} age={props.age} />
}
function CenterTwo(props){
return <Bottom name={props.name} age={props.age} />
}
function Bottom(props){
return <div>{ props.name }{ prps.age }</div>
}
export default Top;
可以看到只有最底下的组件需要这几个值,如果嵌套层数过多会导致中间组件获取无用参数过多,显得过于繁杂。
下面来使用组合方式减少传值数量:
import React from 'react';
function Top(props){
var name = "tom";
var age = "20";
const Bottom = (
<div>{name}{age}</div>
)
return <Center useBottom={Bottom}/>
}
function Center(props){
return <CenterTwo useBottom={props.useBottom}/>
}
function CenterTwo(props){
var useBottom = props.useBottom;
return (
<div>
{useBottom}
</div>
)
}
export default Top;
因为中间的组件不需要这两个值,所以将值直接交给顶层处理,可减少大量无用的值传递。