天天看點

react入門(六):狀态提升&context上下文小白速懂

一、狀态提升

使用 react 經常會遇到幾個元件需要共用狀态資料的情況。這種情況下,我們最好将這部分共享的狀态提升至他們最近的父元件當中進行管理。

原理:父元件基于屬性把自己的一個fn函數傳遞給子元件,子元件在某些操作下把fn執行,在執行fn的過程中把父元件中的一些屬性資訊進行了修改,進而影響相關子元件的重新渲染。

直接看代碼

<Vote title={'标題一'}></Vote>  //調用

vote.js檔案
import React from 'react';
import VoteHeader from './voteHeader.js'
import VoteBody from './voteBody.js'
import VoteFooter from './voteFooter.js'
class Vote extends React.Component{
    constructor(){
        super()
        this.state = {
            n: 0,
            m: 0
        }
    }
    handleNum = (type)=> {
        if (type === 1) {
            this.setState({
                n: this.state.n+1
            })
        } else {
            this.setState({
                m: this.state.m+1
            })
        }
    }
    render() {
        let {title} = this.props;
        let {n, m} = this.state;
        let {handleNum} = this;
        return (
            <div>
                <VoteHeader title={title}></VoteHeader>
                <VoteBody n={n} m={m}></VoteBody>
                //将父元件函數傳遞給子元件調用
                <VoteFooter handleNum={handleNum}></VoteFooter>
            </div>
        )
    }
}
export default Vote;


VoteHeader.js檔案
import React from 'react';
class VoteHeader extends React.Component{
    constructor(){
        super()
    }
    render() {
        let {title} = this.props;
        return (
            <div>{title}</div>
        )
    }
}
export default VoteHeader;


VoteBody.js檔案
import React from 'react';
class VoteBody extends React.Component{
    constructor(){
        super()
    }
    render() {
        let {n, m} = this.props;
        return (
            <div>
                <div>贊成{n}票</div>
                <div>反對{m}票</div>
            </div>
        )
    }
}
export default VoteBody;


VoteFooter.js檔案
import React from 'react';
class VoteFooter extends React.Component{
    constructor(){
        super()
    }
    render() {
        let {handleNum} = this.props;
        return (
            <div>
            //這個地方通過操作父元件函數改變父元件的屬性值
                <button onClick={e => handleNum(1)}>贊成</button>
                <button onClick={e => handleNum(0)}>反對</button>
            </div>
        )
    }
}
export default VoteFooter;           

複制

二、context上下文

基于上下文管理元件資訊的傳遞

上下文也是依托元件嵌套關系完成的,它的優勢在于:目前元件(祖先元件)設定一些上下文,後代所有元件(兒子或孫子等)都可以随時擷取使用,而不需要調取元件的時候層層傳遞。

直接看代碼

<Vote title={'标題一'}></Vote>  //調用

vote.js檔案
import React from 'react';
import PropTypes from 'prop-types';
import VoteHeader from './voteHeader1.js'
import VoteBody from './voteBody1.js'
import VoteFooter from './voteFooter1.js'
class Vote extends React.Component{
    //設定後代需要使用的上下文及類型
    static childContextTypes = {
        title: PropTypes.string,
        n: PropTypes.number,
        m: PropTypes.number,
        handleNum: PropTypes.func
    }
    //擷取後代需要的上下文資訊(可以把這個方法了解為一個生命周期函數,在每一次render之前執行,return的值就是後期需要用到的上下文具體資訊值)
    getChildContext(){
        let {title} = this.props;
        let {n, m} = this.state;
        let {handleNum} = this;
        return {
            title,
            n,
            m,
            handleNum
        }
    }
    constructor(){
        super();
        this.state = {
            n: 0,
            m: 0
        }
    }
    handleNum = (type)=> {
        if (type === 1) {
            this.setState({
                n: this.state.n+1
            })
        } else {
            this.setState({
                m: this.state.m+1
            })
        }
    }
    render() {
        return (
            <div>
                //這裡就不需要再手動傳遞props了
                <VoteHeader></VoteHeader>
                <VoteBody></VoteBody>
                <VoteFooter></VoteFooter>
            </div>
        )
    }
}
export default Vote;


VoteHeader.js檔案
import React from 'react';
import PropTypes from "prop-types"
class VoteHeader extends React.Component{
    //在後代元件中,我們需要用到哪些上下文資訊,一定要指定目前需要使用的資訊值類型(而且必須和祖先指定的一樣),否者無法基于context擷取
    static contextTypes = {
        title: PropTypes.string
    }
    constructor(){
        super()
    }
    render() {
        return (
            //通過上下文的值來進行渲染
            <div>{this.context.title}</div>
        )
    }
}
export default VoteHeader;


VoteBody.js檔案
import React from 'react';
import PropTypes from "prop-types"
class VoteBody extends React.Component{
    static contextTypes = {
        n: PropTypes.number,
        m: PropTypes.number
    }
    constructor(){
        super()
    }
    render() {
        let {n, m} = this.context;
        return (
            <div>
                <div>贊成{n}票</div>
                <div>反對{m}票</div>
            </div>
        )
    }
}
export default VoteBody;


VoteFooter.js檔案
import React from 'react';
import PropTypes from "prop-types";
class VoteFooter extends React.Component{
    static contextTypes = {
        handleNum: PropTypes.func,
    }
    constructor(){
        super()
    }
    render() {
        let {handleNum} = this.context;
        return (
            <div>
                <button onClick={e => handleNum(1)}>贊成</button>
                <button onClick={e => handleNum(0)}>反對</button>
            </div>
        )
    }
}
export default VoteFooter;           

複制