React之Context 上下文模式

React组件树A节点,用Provider提供者注入了theme,然后在需要theme的地方,用Consumer消费者形式取出theme,提供给组件渲染使用。

需要注意的是,提供者永远都需要在消费者上层,正所谓水往低处流,提供者一定要是消费者的某一层父级

  • 老版本的Context

老版本中,React用PropTypes来声明context类型,提供者需要getChildContext来返回需要提供的context,并且用静态属性childContextTypes声明所需要提供的context数据类型。

提供者:

import propsTypes from 'proptypes'
​
class ProviderDemo extends React.Component {
    getChildContext(){
        const theme = {
            color: '#ccc',
            background: 'pink'
        }
        return {theme}
    }
    render () {
        return <div>
            hello,let us learn react!
            <Son></Son>
        </div>
    }
}
​
ProviderDemo.childContextTypes = {
    theme: propsTypes.object
}
​
在老版本中,需要通过getChildContext方法,将传递的theme信息返回出去,并通过childContextTypes 声明要传递的theme是一个对象结构。声明类型需要用propsTypes库来助力

消费者:

// 消费者
class ConsumerDemo extends React.Component{
    render () {
        console.log(this.context.theme)
        const {color,background} = this.context.theme
        return <div style={{color,backgaound}}>消费者</div>
    }
}
​
ConsumerDemo.contextTypes = {
    theme: propsTypes.object
}
​
const Son = () => <ConsumerDemo></ConsumerDemo>
​
作为消费者,需要在组件的静态属性指明我到底需要哪个提供者提供的状态,在demo项目中,ConsumerDemo的contextTyps明确的指明了需要ProviderDemo提供的theme信息,然后就可以通过this.context.theme访问到theme,用来做渲染消费。
  • 新版本的context

最新版中,我们可以直接使用createContext创建出一个context上下文对象,context对象提供两个组件,Providewr和Consumer作为新的提供者和消费者,这种context模式,更便捷的传递context。

  1. createContext

react.createContext 的基本用法如下

const ThemeContext = React.createContext(null) // 创建context
const ThemeProvider = themeContext.Provider // 提供者
const ThemeConsumer = ThemeContext.Consumer // 消费者

createContext接受一个参数,作为初始化context的内容,返回一个context对象,Context对象上的Provider作为提供者,Context对象上的Consumer作为消费者。

  1. 新版本的提供者-Provider用法

const ThemeProvider = ThemeContext.Provider// 提供者
​
export default function ProviderDemo(){
    const [ contextValue , setContextValue ] = React.useState({  color:'#ccc', background:'pink' })
    return <div>
        <ThemeProvider value={ contextValue } > 
            <Son />
        </ThemeProvider>
    </div>
}

Provider 的作用有两个。

a。value属性传递context,提供给消费者使用。

b。value属性改变,themeProvider 会让消费Provider value的组件重新渲染。

  1. 新版消费者

在新版中消费者获取context,提供了三种方式。

  • 类组件中的 contextType方式。

const ThemeContext = React.createContext(null)
// 类组件 - contextType 方式
class ConsumerDemo extends React.Component{
   render(){
       const { color,background } = this.context
       return <div style={{ color,background } } >消费者</div> 
   }
}
ConsumerDemo.contextType = ThemeContext
​
const Son = ()=> <ConsumerDemo />
  1. 类组件的静态属性上的contextType属性,指向需要获取的context,就可以方便获取到最近一层Provider提供的contextValue的值。

  2. 记住这种方式只适用于类组件。

函数组件 useContext方式

在函数组件中,我们使用useContext 来获取上下文。

const ThemeContext = React.createContext(null)
// 函数组件 - useContext方式
function ConsumerDemo(){
    const  contextValue = React.useContext(ThemeContext) /*  */
    const { color,background } = contextValue
    return <div style={{ color,background } } >消费者</div> 
}
const Son = ()=> <ConsumerDemo />

useContext 接受一个参数,就是想要获取的 context ,返回一个 value 值,就是最近的 provider 提供 contextValue 值。

  • 订阅者之 Consumer 方式

     

这种方式,订阅者采用 render props 方式,接受最近一层 provider中的value属性,作为render props函数的参数,可以将参数取出,作为props 混入 consumerDemo组件,说白了就是context 变成了props。

  • 动态的context

function ConsumerDemo(){
     const { color,background } = React.useContext(ThemeContext)
    return <div style={{ color,background } } >消费者</div> 
}
const Son = React.memo(()=> <ConsumerDemo />) // 子组件
​
const ThemeProvider = ThemeContext.Provider //提供者
export default function ProviderDemo(){
    const [ contextValue , setContextValue ] = React.useState({  color:'#ccc', background:'pink' })
    return <div>
        <ThemeProvider value={ contextValue } >
            <Son />
        </ThemeProvider>
        <button onClick={ ()=> setContextValue({ color:'#fff' , background:'blue' })  } >切换主题</button>
    </div>
}

  • 嵌套Provider

    const ThemeContext = React.createContext(null) // 主题颜色Context
    const LanContext = React.createContext(null) // 主题语言Context
    ​
    function ConsumerDemo(){
        return <ThemeContext.Consumer>
            { (themeContextValue)=> (
                <LanContext.Consumer>
                    { (lanContextValue) => {
                        const { color , background } = themeContextValue
                        return <div style={{ color,background } } > { lanContextValue === 'CH'  ? '大家好,让我们一起学习React!' : 'Hello, let us learn React!'  }  </div> 
                    } }
                </LanContext.Consumer>
            )  }
        </ThemeContext.Consumer>
    }
    ​
    const Son = memo(()=> <ConsumerDemo />)
    export default function ProviderDemo(){
        const [ themeContextValue ] = React.useState({  color:'#FFF', background:'blue' })
        const [ lanContextValue ] = React.useState('CH') // CH -> 中文 , EN -> 英文
        return <ThemeContext.Provider value={themeContextValue}  >
             <LanContext.Provider value={lanContextValue} >
                 <Son  />
             </LanContext.Provider>
        </ThemeContext.Provider>
    }

  • 逐层传递Provider

// 逐层传递Provder
const ThemeContext = React.createContext(null)
function Son2(){
    return <ThemeContext.Consumer>
        { (themeContextValue2)=>{
            const { color , background } = themeContextValue2
            return  <div  className="sonbox"  style={{ color,background } } >  第二层Provder </div>
        }  }
    </ThemeContext.Consumer>
}
function Son(){
    const { color, background } = React.useContext(ThemeContext)
    const [ themeContextValue2 ] = React.useState({  color:'#fff', background:'blue' }) 
    /* 第二层 Provder 传递内容 */
    return <div className='box' style={{ color,background } } >
        第一层Provder
        <ThemeContext.Provider value={ themeContextValue2 } >
            <Son2  />
        </ThemeContext.Provider>
    </div>
​
}
​
export default function Provider1Demo(){
    const [ themeContextValue ] = React.useState({  color:'orange', background:'pink' })
     /* 第一层  Provider 传递内容  */
    return <ThemeContext.Provider value={ themeContextValue } >
        <Son/>
    </ThemeContext.Provider> 
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

前端南秋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值