💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
>ContextAPI其实是一个存在了很久的特性,但是旧的API存在很多问题因此使用度不高。React16.3之后官方更新了ContextApi。 之前我们使用传递props的方法在组件之间传值,但是在组件层级多了之后会导致要在每一层都加上要传递的props,维护起来很麻烦,一旦新增或者减少,所有传递了该props的组件都要调整,增加了开发的工作量。为了解决这个问题,React引入了ContextApi <br /> ### Context包含的内容 - React.CreateContext()方法 - 该方法接受一个默认值作为参数,默认值可以为Number,String,Object,Boolean,甚至可以接受一个函数作为参数。 - Context.Provider 上下文支持者组件 - 每一个Context都包含一个Provider组件,该组件接受一个名为value的props,该值将会取代CreateContext中的默认值。一旦使用该组件,就算没有传递value或者value为undefined、NULL,默认值也将不起作用。 - Context.Consumer 上下文消费者组件 - 每一个Context在提供Provider组件的同时也会提供一个Consumer组件,作为该Context的使用者。 - Class.contextType - 所有的类组件都会有一个contextType属性,通过这个属性我们可以把我们创建的context赋值给类组件,并在组件中通过使用this.context来获取当前context的值。 **Consumer可以脱离Provider的情况下单独使用,在没有Provider组件时,将会使用默认值,如果存在多个Provider组件,将会使用最近的Provider组件提供的value作为自己的值** <br /> ### context最基本的应用 ```javascript import React, { Component } from 'react'; const firstContext = React.createContext('一个使用了context的应用'); const ContextComp = () => { return ( <firstContext.Consumer> { contextValue => <h1>{contextValue}</h1> } </firstContext.Consumer> ); }; const ContextFather = () => { return <ContextComp />; }; class ContextTest extends Component { render() { return <ContextFather /> } } export default ContextTest; ``` ![](https://box.kancloud.cn/6811c15595e271a5459a63a0aa7f701c_567x114.png) <br /> ### 使用Context.Provider改变context的值 ```javascript import React, { Component } from 'react'; const firstContext = React.createContext('一个使用了context的应用'); const ContextComp = () => { return ( <firstContext.Consumer> { contextValue => <h1>{contextValue}</h1> } </firstContext.Consumer> ); }; const ContextFather = () => { return <ContextComp />; }; class ContextTest extends Component { render() { return ( <firstContext.Provider value={123}> <ComtextFather /> </firstContext.Provider> ) } } export default ContextTest; ``` ![](https://box.kancloud.cn/e7bf4e571e201012601b3ead39affb6c_229x100.png) <br /> ### 动态设置context值的实现方法 ```javascript import React, { Component } from 'react'; const firstContext = React.createContext('一个使用了context的应用'); const ContextComp = () => { return ( <firstContext.Consumer> { contextValue => <h1>{contextValue}</h1> } </firstContext.Consumer> ); }; const ContextFather = () => { return <ContextComp /> ; }; class ContextTest extends Component { state = { title: 'context测试标题', } render() { return ( <firstContext.Provider value={this.state.title}> <ContextFather /> </firstContext.Provider> ); } } export default ContextTest; ``` ![](https://box.kancloud.cn/0021281d0d897dd9f44eb90aad9552c9_696x165.png) <br /> ### 使用对象作为context的值 ```javascript import React, { Component } from 'react'; const firstContext = React.createContext({ title: '这是一个使用了context的组件' }); const ContextComp = () => { return ( <firstContext.Consumer> { contextValue => <h1>{contextValue.title}</h1> } </firstContext.Consumer> ); }; const ContextFather = () => { return <ContextComp /> ; }; class ContextTest extends Component { state = { title: 'context测试标题', } render() { const { title } = this.state; return ( <firstContext.Provider value={{ title }}> <ContextFather /> </firstContext.Provider> ); } } export default ContextTest; ``` ![](https://box.kancloud.cn/71a6b92200ad447e866828741bed7f2f_641x150.png) <br /> ### 引用外部的Context 在使用中我们可以将Context写入单独的文件,再通过export、import的方式引入Context 在contestTest.jsx中暴露了自定义Context的Provider,Consumer ```javascript import React from 'react'; export const { Consumer, Provider } = React.createContext({ title: '引用外部的context' }); ``` 然后在context.jsx中引入{ Consumer, Provider } ```javascript import React, { Component } from 'react'; import { Provider, Consumer } from './contextTest'; const ContextComp = () => { return ( <Consumer> { contextValue => <h1>{contextValue}</h1> } </Consumer> ); }; const ContextFather = () => { return <ContextComp /> }; class ContextTest extends Component { render() { return ( <Provider value={{ title: '修改引用的外部title' }} <ContextFather /> </Provider> ); } } export default ContextTest; ``` ![](https://box.kancloud.cn/b44394bf733836c57e0208956cbcfa96_492x137.png) <br /> ### 需要注意的点 有人说Context是React中的Redux,在我看来并不是这样。Context有他自己擅长的地方,也有着他的局限性。 1. Context适用于多层级组件之间只用相同的props的情况,一旦组件之间使用的数据结构有一点点变化,我们就需要写一个新的Context来满足组件的使用,如果使用的context是通过引用的方式使用的,那么就需要新写一个context文件,而如果使用props传递的话我们可以选择性的传递部分props或自己拼装新的props。 2. Context的Provier和Consumer是一一对应的,我们需要多少个不同数据结构的Context就需要创建多少个Context,这对于维护来说是不利的。 3. 当Provider传递的value发生变动时,Consumer组件就会更新,且更新不受到shouldComponentUpdate的影响,也就是说即使父组件在shouldComponentUpdate中设定了不更新,Consumer组件也会更新。 4. 其变动判断通过Object.is来判断,会导致不论使用了该Context的组件是否用到了Context中的变动的数据,组件都会更新。 5. Context无法存储数据,其数据的读取全部依靠于Provider组件的value值或者创建时的默认值,因此并不能像Redux那样将数据存储起来,再在页面中引用。建议将Context与State结合起来使用,将Context使用的变量维护在 State当中。当然你可以也将数据维护在Reudx中,这样就没有必要再使用Context了。 <br /> >[info]总的来说,context是React官方借鉴Redux理念的一个实践API,与Redux相比起来,在维护轻量级数据的问题上引用Context比引用Redux要轻量一些。但是Context在使用上也存在着自己的局限性,在实际项目中,复杂、重量级的数据还是应放在Redux中去维护,轻量的数据可以放在Context中去维护。