從入門的角度來聊一下React 的狀態提升。
我們先來看一下React官網是怎么介紹這一概念的:
使用 react 經常會遇到幾個組件需要共用狀態數據的情況。這種情況下,我們最好將這部分共享的狀態提升至他們最近的父組件當中進行管理。
很簡單的一句介紹,由此我們可以很清楚的明白React狀態提升主要就是用來處理父組件和子組件的數據傳遞的;他可以讓我們的數據流動的形式是自頂向下單向流動的,所有組件的數據都是來自于他們的父輩組件,也都是由父輩組件來統一存儲和修改,再傳入子組件當中。
舉個栗子
現在我們需要實現一個統計總價的功能:
1、首先,先寫一個父組件:class Category extends React.Component { constructor(props){super(props);this.state = {name: "React.JS"}}render(){return <h1>{this.state.name}</h1>}
}
ReactDOM.render(<Category />,document.getElementById('app')
)復制代碼
// 子組件
class Children extends React.Component {constructor(props){super(props);}render(){return(<div><label>{this.props.num}<input value={this.props.num} /><button>+</button></label></div>)}
}
// 父組件
class Category extends React.Component {constructor(props){super(props);this.state = {name: "React.JS",num1: 0}}render(){return(<div><h2>{this.state.num1}</h2><Children num={this.state.num1} /></div>)}
}復制代碼
? ? ? 現在我們可以看到,Children這個子組件的數據是從父組件傳下來,通過this.props拿到? ? ? ? ? 的,但是現在還不能在子組件上面去修改父組件的數據,所以我們的子組件的數據也無? ? ? ? ? ? 法得到改變。
3、現在我們在子組件里面定義屬性,來觸發父組件的事件:class Children extends React.Component {constructor(props){super(props);}// input輸入框事件setNum(e){this.props.setNum(e.target.value)}// 按鈕遞增事件addNum(){this.props.addNum()}render(){return(<div><label>{this.props.num}<input onChange={(e)=>this.setNum(e)} value={this.props.num} /><button onClick={()=>this.addNum()}>+</button></label></div>)}
}
class Category extends React.Component {constructor(props){super(props);this.state = {name: "React.JS",// 將子組件的需要用到的數據存放在父組件內,在子組件內通過this.props可以取到num1: 0}}// 處理子組件傳上來觸發input輸入框的處理事件setNum(e){this.setState({num1: parseInt(e)})}// 處理子組件傳上來觸發button按鈕的處理事件addNum(){this.setState({num1: this.state.num1 += 1})}render(){return(<div><h2>{this.state.num1}</h2>// 子組件通過this.props可以觸發對應綁定的事件來修改自身的數據<Children addNum={()=>this.addNum()} setNum={(e)=>this.setNum(e)} num={this.state.num1} /></div>)}
}復制代碼
到這一步,功能已經實現了,子組件通過this.props去拿父組件的數據,并可以觸發屬性上面綁定的對應函數來修改父組件的數據,使子組件的數據得到更新;
其實可以看出,Children這個組件的數據不是獨立的,而是來自Category組件傳下來的,所以,這個Children組件是可以隨意復用的,只需要在他的父組件Category上為他存放一個給她傳遞數據的變量就OK了。
1、首先,我們在Category類的構造函數里的this.state內添加一個新的變量來處理我們即將新? ? ? ?增的另一個子組件:
constructor(props){super(props);this.state = {name: "React.JS",num1: 0,// 添加一個用來處理新組件數據的變量num2: 0 <==================================================}
}復制代碼
2、然后在Category組件里我們再寫一個新的Children組件,屬性上面綁定的數據全部換成們? ? ? ? ?剛才定義的新變量:
render(){return(<div><h2>{this.state.num1}</h2><Children addNum={()=>this.addNum()} setNum={(e)=>this.setNum(e)} num={this.state.num1} /><Children num={this.state.num2} /></div>)
}復制代碼
3、給他綁定屬性事件來修改處理他的變量:
class Category extends React.Component {constructor(props){super(props);this.state = {name: "React.JS",num1: 0,num2: 0}}
// 處理num1數據的子組件setNum(e){this.setState({num1: parseInt(e)})}addNum(){this.setState({num1: this.state.num1 += 1})}
// 處理num2數據的子組件newSetNum(e){this.setState({num2: parseInt(e)})}newAddNum(){this.setState({num2: this.state.num2 += 1})}render(){return(<div>// 這里接收兩個組件的數據總和<h2>{this.state.num1 + this.state.num2}</h2><Children addNum={()=>this.addNum()} setNum={(e)=>this.setNum(e)} num={this.state.num1} />// 在屬性上面綁定新的事件來處理該組件的事件<Children addNum={()=>this.newAddNum()} setNum={(e)=>this.newSetNum(e)} num={this.state.num2} /></div>)}
}復制代碼
現在,看一下實際效果:
*總結:
所以,React的狀態提升,其實是為了組件之間的數據更加單向性,在數據的傳輸上始終只會出現一對一的情況,在處理上,也方便我們只需要在向子組件傳遞數據的那個父輩組件上進行操作,并傳回子組件,使得數據更新,這種方法也體現了React的單向數據流的設計思想,在復用組件的時候,組件的數據也不會相互干擾,使代碼邏輯上會更加便于管理。