es6語法的reactjs的state狀態和組件間props傳遞的實踐

PS:開頭的一段廢話css

       想起一個月前還不知道reactjs該如何下手的而今天有點小體會,仍是有點小欣慰,不過回望一些走過的坑和開始時的滿頭漿糊以爲仍是有點恐怖的。今天分享一點實踐中的當心得給新手朋友們。node

reactjs的es6語法形式

       其餘的就沒必要多說,只說說兩個點:react

  • constructor和superjquery

  • this.functionName=this.functionName.bind(this)webpack

       constructor(props)和super(props)通常是要麼不出現,要麼同時出現,意義實際上就是繼承,這兩個東西其實並非reactjs的,而是es6的,前者就是一個通常意義的構造函數,至關於es5裏面的git

function FunctionName(props) {
    this.props=props;
}

       super(props)則是繼承父類的屬性,(意義至關於es5中的 function Son(name){ Parent.call(this, name) }),並在constructor內部正確拿到this,這個this指向此時的子類。若是在操做this以前(好比console.log(this))沒有寫super(props)則會報錯,意思大概是:不能在super()以前寫this!es6

       而有時候看到constructor()和super(),即沒有寫props好像也沒有什麼問題,緣由天然是沒有在constructor內部用到this.props,實際上在constructor內部通常用到的是this.state居多,貌似this.props沒怎麼寫。。。github

       this.functionName=this.functionName.bind(this)這個是綁定方法到子類上,使得這個this就是當前的子類(所謂的this指向)。還能夠直接將.bind(this)寫函數定義的地方,好比在render渲染的元素上 onClick={this.handleClick.bind(this)}.web

this.state和this.setState({})以及propsName={stateName}

       state在reactjs組件狀態渲染裏面的做用不言而喻,被稱爲狀態渲染機,元素節點的各類屬性值及其改變實際上基本是由state提供的狀態值及其改變完成的。好比元素的文本改變、表單的value值、checked、disabled甚至css樣式均可以作到用state來渲染。如下提供一個簡例輔助說明:ajax

import React from 'react';
import ReactDOM from 'react-dom';
import $ from 'jquery';
class Comp extends React.Component {
    constructor(){
        super();
        this.handleChange=this.handleChange.bind(this);
        this.handleClick=this.handleClick.bind(this);
        this.state={
            value: "",
            msg: ""
        }
    }
    handleChange(e){
        this.setState({
            value: e.target.value
        })
    }
    handleClick(){
        let {value}=this.state;
        $.ajax({
            ...
            data: {
                value:value
            },
            success:(data)=>{
                this.setState({
                    msg: data
                })
            }
        })
    }
    render(){
        let {value,msg}=this.state; 
        return(
            <div>
                <input type="text" value={value} onChange={this.handleChange} />
                <input type="button" value="提交" onClick={this.handleClick} />
                <span>{msg? msg:"此處加載ajax返回的信息"}</span>
            </div>
        )
    }
}
ReactDOM.render( <Comp />, document.body)

       以上簡例在頁面上渲染以後是一個按鈕、一個輸入框和一個信息提示。因爲reactjs提倡單向數據流,在value狀態初始爲空的狀況下,若是直接在輸入框中輸入而不設置value狀態(setState),輸入信息沒法獲取。這個渲染過程是:首先頁面加載時根據默認的this.state中的三個狀態值生成相應的狀態,onChange事件不斷改變state的value值,此時state接收到了改變並立刻從新渲染頁面上輸入框內的值,即:只要任何動做改變了state值,頁面就會從新渲染相應的地方(關於其餘reactjs入門案例demo能夠參見本人的github)。

props屬性以及傳遞

       注意一下,以上說constructor內若是沒有傳遞props參數,其內部就不能使用this.props。但這並不意味着其餘地方好比render內部不能使用。目前只是體會到組件之間傳遞的props值的初始來源通常都是state值,多是實踐不夠的緣由 @_@。。。

1.父組件向子組件傳值

       這是比較常見的父子組件之間通訊的方式。子組件上的屬性值能夠理解爲一個參數,而須要父組件傳遞一個實際值。傳值這種方式通常是複用組件所必需的,由於有可能有多個頁面的內容的某一個部分高度類似甚至相同,這時只須要對一個組件傳遞不一樣的值就能夠實現屢次利用。以下例:

假定組件文件都在根目錄下:
//子組件Son.js
class Son extends React.Component{
    render(){
        let {title,userValue,pwdValue,handleChange,handleSubmit}=this.props;
        return(
            <div>
                <h3>{title}</h3>
                <input type="text" value={userValue} onChange={(e)=>handleChange("user",e.target.value} />
                <input type="password" value={pwdValue} onChange={(e)=>handleChange("pwd",e.target.value} />
                <input type="button" value="提交" onClick={handleSubmit} />
            </div>
        )
    }
}
//父組件1:Login.js
import Son from './Son.js';
class Login extends React.Component{
    constructor(){
        super();
        this.handleChange=this.handleChange.bind(this);
        this.handleSubmit=this.handleSubmit.bind(this);
        this.state={
            user:{
                value:"",
                error:false
            },
            pwd:{
                value:"",
                error:false
            }
        }
    }
    handleChange(field,val){
        let newState={value:val, error:true};
        switch(field) {
            case "user":
                if (!val.length){
                    newState.error=false
                } else if (val.length>4) {
                    newState.error=false
                }
                this.setState({
                    user:newState
                })
                break;
            case "pwd":
                if (!val.length){
                    newState.error=false;
                } else if (val.length>6) {
                    newState.error=false
                }
                this.setState({
                    pwd:newState
                })
                break;
        }
    }
    handleSubmit() {
        let {user, pwd}=this.state;
        if (!user.error || !pwd.error) {
            alert("請重試!");
            return;
        } else {
            $.ajax({
                ...
                data: {
                    username: user.value,
                    password: pwd.value
                },
                ...
            })
        }
    render(){
        let {user, pwd}=this.state;
        return(
            <Son title="請登陸" userValue={user.value} pwdValue={pwd.value} handleChange={this.handleChange} handleSubmit={this.handleSubmit} />
        )
    }
}

       相信各位看得出來,這是個登陸頁面的雛形,其中僅限原理說明,先不要糾結規範什麼的哈。。。通常來講,既然有登陸,也就有註冊,註冊頁面基本上也是這個道理。須要說明的是:子組件上的屬性值和方法都是this.props的,這裏之因此沒有寫this.handleChange或者this.handleSubmit是由於子組件自己沒有這個方法,所以若是此時在子組件上的方法前加上this.xxx就會報錯大概說這個方法不是個函數!屬性值也類似;同時利用拆包表達式寫this.props表示這些屬性和方法都是從父組件上繼承而來,只要父組件上定義了方法,所以子組件上此時能夠不用寫constructor()和super()。

2.父組件的父組件子組件傳值

       這個場景主要用於組件嵌套比較多的時候。好比,咱們發如今子組件Son.js中,有三個輸入框分別是用戶名、密碼,但貌似有點不三不四,那麼咱們就完善一點這個表單:

新建組件Form.js
class Form extends React.Component{
    render(){
        let {handleSubmit, userValue, pwdValue, handleChange}=this.props;
        return(
            <form  onSubmit={handleSubmit} method="post" action="/submit">
                <input type="text" name="user" value={userValue} onChange={(e)=>handleChange("user",e.target.value} />
                <input type="password" name="pwd" value={pwdValue} onChange={(e)=>handleChange("pwd",e.target.value} />
                <input type="submit" />
            </form>
        )
    }
}

       有了這個組件以後,關於表單的Son.js組件能夠改形成(一樣假定全部組件都在根目錄下):

//Son.js
import Form from  './Form.js';
class Son extends React.Component{
    render(){
        let {title,userValue,pwdValue,handleChange,handleSubmit}=this.props;
        return(
            <div>
                <h3>{title}</h3>
                <Form 
                    userValue={userValue}
                    pwdValue={pwdValue}
                    handleChange={handleChange}
                    handleSubmit={handleSubmit}
                />
            </div>
        )
    }
}

       也許新手童鞋們不太明白Son.js組件上的屬性和方法命名究竟是不是必定要和孫子級組件上的同樣,由於本人在學這個地方的時候的確糾結過,不過請注意:只要onChange或者onSubmit這類元素上原生方法後指定的一個函數(Form.js),好比onChange={handleChange},那麼這個handleChange在傳遞的時候,上級組件(Son.js)上的handleChange={handleChange}中,左邊是上級組件的方法,能夠新命名好比footChange。。。而右邊則是傳遞給下級組件的方法handleChange,因此,下級組件Form.js中onChange的右邊函數名必須對應之。

       此外,咱們還能夠根據Son.js作個簡單的歡迎頁:

//Welcome.js
class Welcome extends React.Component{
    render(){
        return(
            <h1>歡迎您!</h1>
        )
    }
}
//SonWelcome.js
import Welcome from './Welcome.js';
class SonWelcome extends React.Component{
    render(){
        return(
            <div>
                <h3>{this.props.title}</h3>
                <Welcome />
            </div>
        )
    }
}

       固然,SonWelcom.js太過簡單了。。。同時title的值依賴於上一級組件傳值肯定,兄弟們大開腦洞吧。

3.非上下級關係和非兄弟的組件之間如何傳值

       相信這個狀況是比較少的,不過這是個值得研究的,有一些師兄和大神們確定知道如何解決。所謂的兄弟組件就是具備共同的父組件或者「爺組件」的多個組件,這種狀況和以上差很少,主要把兄弟組件之間須要的共同的值掛載到上級組件便可。而非上下級和非兄弟組件這種狀況的應用場景有點相似(注意,僅僅是相似)session或者cookie,好比有多個頁面須要根據用戶是否登陸或者是不是管理員超級用戶來對頁面進行不一樣的渲染。
       先說說能夠解決的途徑吧,首先推薦的是一個js庫:PubSubJs,詳情能夠去了解一下(實際我也沒用過。。。)。其次,說說本人的想法吧。正如上所言,假設這個屬性或者方法在渲染組件的時候並不涉及安全性問題,那麼何不將其設置爲cookie或者session呢?哪一個組件須要這個值就將其提出來。以下例兩個組件:
暫且寫以下,先無論自定義flag從何而來,同時,.active的樣式是:display:none;

//CompOne.js
class CompOne extends React.Component{
    render(){
        return(
            <div>
                <p className={flag? "":"active"}>這個第一個組件</p>
            </div>
        )
    }
}
//CompTwo.js
class CompTwo extends React.Component{
    render(){
        return(
            <div>
                <p className={flag? "active":""}>這個第二個組件</p>
            </div>
        )
    }
}

       假設以上兩個組件並無關係,且都帶有一個共同的自定義屬性flag,這兩個組件根據flag的意義進行隱藏或展現。此時,能夠建一個組件Cookie內部封裝一個構造函數HandleCookie,內部封裝三個方法setCookie(name, value, time),getCookie(name),clearCookie(name, value, time)。假設,name是cookie名稱,value是cookie的值,time參數是參照當前時間的cookie的保存時間長度,設置爲1表示一天後過時,設置-1則表示過時失效。

       照此假定,以上兩個組件能夠直接在渲染頁面的時候取到cookie的flag名稱對應的值,並根據值渲染頁面。好比在項目的某個文件加載完畢(componentDidMount)的時候設置一個cookie:{flag:"1"},CompOne.js:

//CompOne.js
import Cookie from './Cookie.js';
class CompOne extends React.Component{
    render(){
        let flag=Cookie.getCookie("flag");
        return(
            <div>
                <p className={flag? "":"active"}>這個第一個組件</p>
            </div>
        )
    }
}

       照此安排,這個組件CompOne渲染後就會展現,而CompTwo則會隱藏。不過,這種方式明顯不是一種規範的方法,僅僅是想法而已,望輕噴!

寫在結尾的話

       以上如有不當之處,還請指正一下,給小弟一個改過自新的機會吧。。。若是童鞋還對其餘沒有寫完全的地方感興趣,能夠參見本人的一個留言本小項目,乃是本國reactjs、webpack配置、nodejs和express入門的最好材料之一,以爲好用就star一下吧,哎,求star真很差意思^_^

相關文章
相關標籤/搜索