React 进阶 context

作者: zidea | 来源:发表于2019-05-13 11:18 被阅读32次
react

纵观前端框架,在国内还是 vue 和 react 是比较受欢迎的。angular 较他们要显得稍弱一些。我接触 react 自认为比较早,但是还没有实际将其应用到大型应用中的经验。今天我们看一看 react,最近也是重新将其捡起,有说的不对地方还希望大家指正。

今天我们来谈一谈 context ,我们知道 react 中数据流是单向传递的,如果数据流从顶层一路流到底层是比较耗时耗力的。我们通过实例来进行说明问题所在。

import React, { Component } from 'react';

class Greeting extends Component{
  
    render(){
        return(
            <div>
                <p>zidea</p>
            </div>
        )
    }
}

export default Greeting;
import React from 'react';
import './App.css';

import Greeting from './Context/Greeting';

// const Extended

function App() {
  return (
    <div>
      <Greeting/>
    </div>
  );
}

export default App;

我们使用 create-react-app 创建应用后对代码进行调整,删除一些我们不需要的模板代码。

    state = {
        name:'zidea',
        age:35,
        married:true
    }

在 Greeting 定义 state 对象,包含数据,然后创建一个 Person 组件,这个组件将会消费 Greeting 组件中 state 数据。

class Person extends Component{
    render(){
        return (
            <div className="person">
                <p>i am zidea</p>
            </div>
        )
    }
}

class Greeting extends Component{

    state = {
        name:'zidea',
        age:35,
        married:true
    }
    
    render(){
        return(
            <div>
                <Person/>
            </div>
        )
    }
}
    render(){
        return(
            <div>
                <Person name={this.state.name}/>
            </div>
        )
    }

可以通过 prop 将数据传递给 Person,然后在 Person 组件中通过 this.props.name来消费 name 传递过来值。

class Person extends Component{
    
    render(){
        return (
            <div className="person">
                <p>i am {this.props.name}</p>
            </div>
        )
    }
}

创建中间组件 Family 来包裹 Person 组件。随后我们数据传递需要经过 Family 组件传递给 Person 组件。

const Family = (props) => (
    <div className="family">
        <Person/>
    </div>
)
class Greeting extends Component{

    state = {
        name:'zidea',
        age:35,
        married:true
    }
    
    render(){
        return(
            <div>
                <Family/>
            </div>
        )
    }
}

如果再多了一层 Family ,我们在 Greeting 定义数据需要经过 Family 组件传递给 Person 组件。

const Family = (props) => (
    <div className="family">
        <Person name={props.name}/>
    </div>
)

class Person extends Component{
    
    render(){
        return (
            <div className="person">
                <p>i am {this.props.name}</p>
            </div>
        )
    }
}

class Greeting extends Component{

    state = {
        name:'zidea',
        age:35,
        married:true
    }
    
    render(){
        return(
            <div>
                <Family name={this.state.name}/>
            </div>
        )
    }
}

这样问题就是我们在顶层 Greeting 定义组件中定义数据需要层层传递给这些数据消费者 Person,中间经过了中间商 Family,其实我们希望厂家直接面对消费者,没有中间商。让我想起了淘宝。其实这里还好中间只有一层,在实际开发中中间层组件可能会有很多,所以我们就需要 context 来消除数据传递的中间层组件。

创建 React.createContext() 创建一个 Context 作为上下文对象,

const MContext = React.createContext();

//创建 provider
class MProvider extends Component{
    state = {
        name:'zidea',
        age:35,
        married:true
    }

    render(){
        return(
            <MContext.Provider>
                {this.props.children}
            </MContext.Provider>
        )
    }

}

然后创建 MProvider 组件来在 Context 中提供了

  • provider 提供者
  • consumer 消费者
    Context 类似淘宝提供一个平台,让厂家(Provider)和消费者(Consumer)可以直接面对面。
    需要用 MContext.Provider 包裹我们组件
import React, { Component } from 'react';

const MContext = React.createContext();

//创建 provider
class MProvider extends Component{
    state = {
        name:'zidea',
        age:35,
        married:true
    }

    render(){
        return(
            <MContext.Provider>
                {this.props.children}
            </MContext.Provider>
        )
    }

}

const Family = (props) => (
    <div className="family">
        <Person/>
    </div>
)

class Person extends Component{
    
    render(){
        return (
            <div className="person">
                <p>this is wrapped by provider</p>
            </div>
        )
    }
}


class Greeting extends Component{

    render(){
        return(
            <MProvider>
                <div>
                    <Family/>
                </div>
            </MProvider>
        )
    }
}


export default Greeting;

我们去掉通过 props 来传递数据的逻辑,然后 MContext.Provider 中定义属性 value 我们的值是通过 provider 的 value 属性传递给 consumer 的。

    render(){
        return(
            <MContext.Provider value="zidea">
                {this.props.children}
            </MContext.Provider>
        )
    }
class Person extends Component{
    
    render(){
        return (
            <div className="person">
                <MContext.Consumer>
                    {(context)=>(
                        <p>I am {context}</p>
                    )}
                </MContext.Consumer>
            </div>
        )
    }
}

值已经从 Provider 传递出来了,那么我们如何在 Person 中接收数据呢,这时候需要用到 Context 的 Consumer 组件在组件我们可以通过自定义一个函数来接收 context 这个 context 就负责接收 provider 中 value 的值。
以此来实现数据在 Provider 和 Consumer 间传递。除了传递数据我们也可以传递行为。

class MProvider extends Component{
    state = {
        name:'zidea',
        age:35,
        married:true
    }

    render(){
        return(
            <MContext.Provider value={{
                state: this.state
            }}>
                {this.props.children}
            </MContext.Provider>
        )
    }

}
class Person extends Component{
    
    render(){
        return (
            <div className="person">
                <MContext.Consumer>
                    {(context)=>(
                        <React.Fragment>
                            <p>I am {context.state.name}</p>
                            <p>I am {context.state.age} year old</p>
                        </React.Fragment>
                    )}
                </MContext.Consumer>
            </div>
        )
    }
}
class MProvider extends Component{
    state = {
        name:'zidea',
        age:35,
        married:true,
        level:5
    }

    render(){
        return(
            <MContext.Provider value={{
                state: this.state,
                changeMarryState : (b) => this.setState({
                    married:b
                }),
                incrementLevel :() => this.setState({
                    level:this.state.level + 1
                })
            }}>
                {this.props.children}
            </MContext.Provider>
        )
    }

}

const Family = (props) => (
    <div className="family">
        <Person/>
    </div>
)

class Person extends Component{
    
    render(){
        return (
            <div className="person">
                <MContext.Consumer>
                    {(context)=>(
                        <React.Fragment>
                            <p>I am {context.state.name}</p>
                            <p>I am {context.state.age} year old</p>
                            <p>I am {context.state.level} level</p>
                            <button onClick={context.incrementLevel} >increment level</button>
                        </React.Fragment>
                    )}
                </MContext.Consumer>
            </div>
        )
    }
}
javascript-illustration.png

相关文章

  • react进阶-Context

    基于react父子组件互相嵌套的基础,在复杂结构中,一定会出现层层嵌套的情况。导致父子组件相隔甚远,遥遥不可相见。...

  • React 进阶 context

    纵观前端框架,在国内还是 vue 和 react 是比较受欢迎的。angular 较他们要显得稍弱一些。我接触 r...

  • 2018-08-08

    React 高级指南 React 新版上下文(context) context ?答:上下文(Context) 提...

  • React 进阶目录

    React进阶(附录一)构建工具改造过程记录 React进阶(一)React进阶更新计划浅谈React进阶(二)为...

  • React中不常用的功能——Context

    React中不常用的功能——Context Context React源码版本16.8 基本用法 跨层级通信 Co...

  • React 进阶提高 - 技巧篇 - React Hook -

    React 进阶提高 - 技巧篇 - React Hook - 第 2 季(18 个视频) React 进阶提高 ...

  • 疑问汇总

    1. react context是怎样实现 跨组件通信的? 从Context源码实现谈React性能优化[http...

  • Context 进阶

    种写法就相当于我们把全局Context对象通过参数传递给了LitePal,效果和在清单文件配置LitePalApp...

  • react context

    react context React.createContext, Provider(数据提供者), Consu...

  • React 拾遗之 Context

    React 拾遗之 Context React.js 的 context 其实像就是组件树上某颗子树的全局变量 使...

网友评论

    本文标题:React 进阶 context

    本文链接:https://www.haomeiwen.com/subject/pjixaqtx.html