React 頁面間傳值的我的總結

react 組件之間傳值的方案有不少,下面是我我的經驗的總結
github 地址javascript

props 來傳遞值

傳值方式:
  • 經過props 獲取值
  • 經過props 提供的func去修改值
優勢:
  • 不須要任何第三方的組件,純react,很是純哦
缺點:
  • 代碼調試有些麻煩,可是能夠react 插件輔助查看到當前react 對象的props
注意事項:

通常在表單頁面中用到組件時候會用到props 傳遞值,須要注意下,最好頁面的狀態控制都在該頁面的頂級節點的state 的,不要嘗試獲取或控制子節點的state,因此組件內部state是父級節點不關心的java

Demo 代碼以下:
import React,{Component} from 'react';
import PropTypes from 'prop-types'

class ChildNode extends Component{
    static PropTypes={
        value:PropTypes.string.isRequired,
        onChange:PropTypes.func.isRequired
    }
    render(){
        const {value,onChange} = this.props;
        return (
            <div>
                <span>這裏是子節點值:{value}</span><br/>

                <input type="text" value={value} onChange={(e)=>{
                    console.log('開始更改值')
                    onChange(e.target.value)
                }}/>
            </div>
        )
    }
}


class Parent extends Component{
    state={
        childValue:'this is the value of the child node'
    }
    onChildValueChange=(val)=>{//注意這裏用ES6 的array function 來綁定當前的this
        this.setState({childValue:val})
    }
    render(){
        const {childValue} = this.state;
        return (
            <div>
                <span>這裏是父節點</span>
                <div>
                    <span>父節點控制子節點的內容</span>
                    <button onClick={()=>{
                        let childValue = this.state.childValue||""
                        this.setState({
                            childValue:childValue+'我最帥!'
                        })
                    }}>內容直接加上我最帥</button>
                </div>
                <br/>
                <br/>
                <ChildNode value={childValue} onChange={this.onChildValueChange}/>
            </div>
        )
    }
}


export default Parent;

Redux

這裏使用redux-react 來鏈接 react 和 redux。node

傳遞方式:

獲取值:經過redux-react connect()react

傳遞值:經過dispatch 具體的actiongit

優勢:
  • 能夠經過redux-logger 組件來查看數據的變化過程,能夠容易的調試複雜的業務邏輯
  • 全局的數據均可以獲取到以及修改
缺點:
  • 由於業務獨立邏輯代碼獨立到action、reducer裏面,須要增長code的代碼量以及單獨action、reducer文件的分割。

能夠藉助文件夾名稱的約定和第三方組件來彌補上面的缺點github

注意事項

經過connect 傳遞過來的props 值不能修改哦。只讀的!redux

Demo 代碼以下:
import React,{Component} from 'react'
import {createStore,combineReducers} from 'redux'
import { Provider,connect } from 'react-redux'

/**
 * reducer 用來描述state 是怎樣改變的
 * @param state
 * @param action
 * @returns {number}
 */
function reducerOne(state=0,action){
    switch (action.type) {
        case 'reducerOne/INCREMENT':
            return state + 1
        case 'reducerOne/DECREMENT':
            return state - 1
        default:
            return state
    }
}

const store = createStore(combineReducers({reducerOne}))

class ReduxNodeOne extends Component{
    render(){
        return (
            <div>
                <h6>節點一</h6>
                <button onClick={()=>{
                    this.props.increment()
                }}>加1</button>
                <button onClick={()=>{
                    this.props.decrement()
                }}>減1</button>
            </div>
        )
    }
}
class ReduxNodeTwo extends Component {
    render(){
        return (
            <div>
                <h6>節點二</h6>
                <span>Counter:{this.props.counter}</span>
            </div>
        )
    }
}
const ConnectedReduxNodeTwo = connect(({reducerOne})=>{
    return {
        counter:reducerOne
    }
})(ReduxNodeTwo)

const ConnectedReduxNodeOne= connect(null,{
    increment:function(){
        return {
            type:'reducerOne/INCREMENT'
        }
    },
    decrement:function(){
        return {
            type:'reducerOne/DECREMENT'
        }
    }
})(ReduxNodeOne)

export default function(){
    return (
        <Provider store={store}>
            <div>
                <h1>Redux Simple Demo</h1>
                <ConnectedReduxNodeOne />
                <ConnectedReduxNodeTwo/>
            </div>
        </Provider>
    )
};

context

純react 頁面的時候,若是數據的傳遞要經過多層react 對象的時候,你能夠考慮context 傳遞值哦。框架

傳遞方法:

獲取值:子組件內定義static contextTypes={ name:PropTypes.string.isRequired, } 在經過this.context 去獲取ide

傳遞值:父組件定義static childContextTypes={ name:PropTypes.string }getChildContext(){ return { name:'爺爺' } }ui

優勢:
  • 能夠透過多層react 傳值
缺點:
  • 有點打亂數據傳遞的流向,很差理解數據
注意事項:
  • 通常在寫通用性組件的時候纔會用到,其餘時候儘可能用props 或者 redux 去實現

Demo 以下:

import React,{Component} from 'react'
import PropTypes from 'prop-types'

class ContextParent extends Component{
    static childContextTypes={
        name:PropTypes.string
    }
    render(){
        return (
            <div>
                Node Parent
                {this.props.children}
            </div>
        )
    }

    getChildContext(){
        return {
            name:'爺爺'
        }
    }
}

class Context extends Component{
    render(){
        return <div>
            Current Node
            {this.props.children}
        </div>
    }
}

class ContextChild extends Component{
    static contextTypes={
        name:PropTypes.string.isRequired,
    }
    render(){
        return (
            <div>
                Node Children
                <span>Parent:{this.context.name}</span>
            </div>
        )
    }
}

export default function(){
    return (
        <ContextParent>
            <Context>
                <ContextChild/>
            </Context>
        </ContextParent>
    )
}

event 傳值

經過 eventemitter3 library 實現,也能夠用其餘的event 庫

該傳值方案通常做爲react state 存儲數據時候須要聯動觸發的業務邏輯以及專業填上線前出現的業務邏輯的代碼坑。

傳值方式:

獲取值:經過在constructor 裏面監聽event 事件,再setState到內部state

傳遞值: 觸發 emit 事件

優勢:
  • 事件驅動,能夠和其餘框架作數據交換
缺點
  • 數據流向不明確,很差理解和後續維護
注意事項
  • event 的 事件名稱 最好是全局的constants 對象,同時也是有規律的
Demo 以下:
import React,{Component} from 'react'
import EventEmitter from 'eventemitter3';
const EVENT = new EventEmitter();

class NodeOne extends Component{
    constructor(props){
        super(props)
        this.state={
            counter:0
        };
        EVENT.on('NodeOne:increment',(num)=>{
            this.setState({
                counter:this.state.counter+num
            })
        })
    }
    render(){
        return (
            <div>
                <h4>Node One 當前counter:{this.state.counter}</h4>
                <button onClick={()=>{
                    EVENT.emit('NodeTwo:increment',20)
                }}>Node Two 加 20</button>
            </div>
        )
    }
}

class NodeTwo extends Component{
    constructor(props){
        super(props)
        this.state={
            counter:0
        };
        EVENT.on('NodeTwo:increment',(num)=>{
            this.setState({
                counter:this.state.counter+num
            })
        })
    }
    render(){
        return (
            <div>
                <h4>Node Two當前counter:{this.state.counter}</h4>
                <button onClick={()=>{
                    EVENT.emit('NodeOne:increment',5)
                }}>Node One 加 5</button>
            </div>
        )
    }
}

export default function(){
    return (
        <div>
            <NodeOne/>
            <NodeTwo/>
        </div>
    )
}
相關文章
相關標籤/搜索