聊聊React的Context

yvonne

Context概念

一般用在跨组件通信中。

image.png

如上面的组件树中,A组件与B组件之间隔着非常多的组件,假如A组件希望传递给B组件一个属性,那么不得不使用props将属性从A组件历经一系列中间组件传递给B组件。
这样代码不仅非常的麻烦,更重要的是中间的组件可能压根就用不上这个属性,却要承担一个传递的职责,这是我们不希望看见的。
Context出现的目的就是为了解决这种场景,使得我们可以直接将属性从A组件传递给B组件。

旧Context(不推荐使用)

过时的API官方文档传送门

基本用法

假定,ABC三个组件,AC为祖孙关系,AB父子关系,现在使用context由A向C传递属性text

class A extends React.Component {
    getChildContext() {
        return { text: 'Hello孙子' }
    }
    render() {
        return (
            <div>组件A包含<B/></div>
        )
    }
}

A.childContextTypes = { text: PropTypes.string };

class B extends React.Component {
    render() {
        return (
            <div>组件B包含<C/></div>
        )
    }
}

class C extends React.Component {
    render() {
        const { text } = this.context;
        return (
            <div>我是C我接收到A传递的内容是{text}</div>
        )
    } 
}

C.contextTypes = { text: PropTypes.string }

留意上述代码中用以提供contextAPI,只要给上层组件添加getChildContextchildContextTypesReact将自动向下传递信息,子树上的所有组件可以通过定义 contextTypes 来访问 context

带来的问题

假如我们想要更新context,那么只能通过更新state或者props并将其值赋值给context

class A extends React.Component {
    constructor(props) {
        super(props);
        this.state = { text: 'Hello孙子' };
    }
    getChildContext() {
        return { text: this.state }
    }
    updateState = () => {
        this.state = { text: '我是你爷爷' };
    }
    render() {
        return (
            <div onClick={this.updateState} >组件A包含<B /></div>
        )
    }
}

A.childContextTypes = { text: PropTypes.string };

但是,如果A组件提供的一个context发生了变化,而中间父组件(B)的 shouldComponentUpdate 返回 false,那么实际上B和C都不会进行更新。使用了context的组件则完全失控,所以基本上没有办法能够可靠的更新context

新Context

官方文档传送门

还是上述例子,AC祖孙组件通信。使用createContext可以构建一个Provider用以给孙子组件传递props

const defaultVal = { text: 'Hello,孙子' };
const AContext = React.createContext(defaultVal);

class App extends React.Component {
    constructor(props) { 
        ...,
        this.state = { text: '这里是新的内容' }
    }
    render() {
        return (
            <AContext.Provider value={this.state}>
                <B />
            </AContext.Provider>
        )
    }
}

// 接收方式1-定义contextType
import { AContext } from './A';
class C extends React.Component {

    static contextType = AContext;
    
    render() {
        const { text } = this.context;
        return (
            <div>我是C我接收到A传递的内容是{text}</div>
        )
    } 
}

// 接收方式2-使用consumer
// consumer主要用以函数组件渲染
import { AContext } from './A';

class C extends React.Component {
    render() {
        return (
            <AContext.Consumer>
                ({ text }) => (
                    <p>我是C我接收到A传递的内容是{text}</p>
                )
            </AContext.Consumer>
        )
    } 
}

Redux中的Context

// 待续补坑
阅读 135

Nodes of Front-end
前端妹砸的笔记本。。

少年(゚∀゚ )有兴趣来鹅厂吗?欢迎投简历至yvonnexchen@tencent.com

1.2k 声望
57 粉丝
0 条评论
你知道吗?

少年(゚∀゚ )有兴趣来鹅厂吗?欢迎投简历至yvonnexchen@tencent.com

1.2k 声望
57 粉丝
宣传栏