40

React之context

 5 years ago
source link: http://blog.poetries.top/2018/07/23/react-context/?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
  • React 组件之间的通信是基于 props 的单向数据流,即父组件通过 props 向子组件传值,亦或是子组件执行传入的函数来更新父组件的 state ,这都满足了我们大部分的使用场景
  • 一般地,对于兄弟组件之间的通信,是通过它们共同的祖先组件进行的,即 Lifting State Up,官方文档也有介绍。组件一通过事件将状态变更通知它们共同的祖先组件,祖先组再将状态同步到组件二
  • 但是,如果组件之间嵌套的比较深,即使提升状态到共同父组件,再同步状态到相应的组件还是需要一层一层的传递下去,可能会比较繁琐
  • 在对应的场景中, context 就可以缩短父组件到子组件的属性传递路径

例1

import Parent from './Parent'
import ChildOne from '../components/ChildOne'
import ChildTwo from '../components/ChildTwo'

export default class Container extends React.Component {
    constructor(props) {
        super(props);
        this.state = { value: '' }
    }

    changeValue = value => {
        this.setState({ value })
    }

    getChildContext() {
        return {
            value: this.state.value,
            changeValue: this.changeValue
        }
    }

    render() {
        return (
            <div>
                <Parent>
                    <ChildOne />
                </Parent>
                <Parent>
                    <ChildTwo />
                </Parent>
            </div>
        )
    }
}

Container.childContextTypes = {
    value: PropTypes.string,
    changeValue: PropTypes.func
}

Parent.jsx

import React from "react"

const Parent = (props) => (
    <div {...props} />
)

export default Parent

ChildOne.jsx

export default class ChildOne extends React.Component {

    handleChange = (e) => {
        const { changeValue } = this.context
        changeValue(e.target.value)
    }

    render() {
        return (
            <div>
                子组件一
                <input onChange={this.handleChange} />
            </div>
        )
    }
}

ChildOne.contextTypes = {
    changeValue: PropTypes.func
}

ChildTwo.jsx

export default class ChildTwo extends React.Component {
    render() {
        return (
            <div>
                子组件二
                <p>{this.context.value}</p>
            </div>
        )
    }
}

ChildTwo.contextTypes = {
    value: PropTypes.string
}

Container.childContextTypes 中进行接口的声明,通过 getChildContext 返回更新后的 state ,在 Child.contextTypes 中声明要获取的接口,这样在子组件内部就能通过 this.context 获取到。通过 Context 这样一个中间对象, ChildOneChildTwo 就可以相互通信了

例2

组件嵌套传递属性,在导航里面引用 Page 中的变量

context

使用 context 组件需要定义 propTypes ,需要严格校验、声明类型、字段

class Page extends React.Component {
    static childContextTypes = {
       user:PropTypes.string
    }
    constructor(props){
        super(props)
        this.state = {user:'poetries'}
    }
    getChildContext(){
        return this.state
    }
    render(){
        return (
          <div>
            <p>我是{this.state.user}</p>
            <Siderbar />
          </div>
        )
    }
}

class Siderbar extends React.Component {
    static childContextTypes = {
       user:PropTypes.string
    }
    render(){
        return (
          <div>
            <p>侧边栏</p>
            <Navbar />
          </div>
        )
    }
}
class Navbar extends React.Component {
    static childContextTypes = {
       user:PropTypes.string
    }
    render(){
        return (
          <div>
            <p>我是{this.context.user}的导航栏</p>
            <Siderbar />
          </div>
        )
    }
}

context在Provider种应用

provider 组件就是使用 context ,把 store 放到 context 里,所有的子元素可以直接取到 store

import PropTypes from 'prop-types'
class Provider extends Component {
    static childContextTypes = {
        store:Protypes.object
    }
    constructor(props,context){
        super(props,context)
        this.store = props.store
    }
    getChildContext(){
        //把传进来的store放进全局
        return {store:this.store}
    }
    render(){
        return this.props.children
    }
}

connect 负责连接组件,给到 redux 里的数据放到组件的属性里

state
//高阶组件写法
const connect = (mapStateToProps=state=>state,mapDispatchToProps={})=>(wrapperComponent)=>{
    return class ConnectComponent extends React.Component {
        //负责接收组件
        static contextTypes = {
            store:PropTypes.obejct
        }
        constructor(props){
            super(props, context){
                this.state = {
                    props:{}
                }
            }
        }
        componentDidMount(){
            const {store} = this.context
            store.subscribe(()=>this.update())
            this.update()
        }
        update(){
            //  获取mapStateToProps、mapDispatchToProps 放入this.props里
            
            const {store}=this.context
            const stateProps = mapStateToProps(store.getState())
            const dispatchProps = bindActionCreators(mapDispatchProps,store.dispatch)
            this.setState({
                props:{
                    ...this.state.props,
                    ...stateProps,
                    ...dispatchProps
                 }
            })
        }
        render(){
            // 把数据放入
            return <wrapperComponent {...this.state.props}/>
        }
    }
}

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK