react的狀態(tài)提升

????????在react中是單向數(shù)據(jù)流的設(shè)計(jì),?即?只有父組件可以傳遞數(shù)據(jù)給子組件,而沒有子組件傳遞數(shù)據(jù)給父組件的概念.?以正確的技術(shù)說明,是 擁有者組件 可以設(shè)置 被擁有者組件 中的資料,也就是主人與仆人的關(guān)系。

那么子組件要傳遞數(shù)據(jù)給父組件該如何溝通呢?

換句話說就是,?react 如何將子組件的值暴露讓父組件獲取到?

????????可以采用一種迂回的方法,?在父組件中設(shè)置一個(gè)方法(函數(shù)),?將其通過props傳遞給子組件,?然后在子組件中更新state的狀態(tài),并調(diào)用父組件中傳過來的方法,?將state數(shù)據(jù)作為參數(shù)傳遞給父組件.?這樣,?改變父組件的狀態(tài),從而改變受父組件控制的所有子組件的狀態(tài).?這就是狀態(tài)提升的概念.? ?用官方的原話就是:? ? '共享 state(狀態(tài)) 是通過將其移動(dòng)到需要它的組件的最接近的共同祖先組件來實(shí)現(xiàn)的。 這被稱為“狀態(tài)提升(Lifting State Up)'。

? ? 官方參考網(wǎng)址:?http://www.css88.com/react/docs/lifting-state-up.html

? ? 下面舉個(gè)例子說明:

? ? ? ? App.js文件? ?

import? React, { Component } from 'react'

import Item from './Item'

export default class App extends Component {

????constructor(props) {

????????super(props)

????????this.state = {

????????????options: [

????????????????{name:'(1)免費(fèi)行李', value: 1 },

????????????????{name:'2', value: 2 },

????????????????{name:'3', value: 3 } ],

????????????price: 0

????????}

? ?}

????changePrice = (value) => {

????????let price = 800

????????if(value === 1)? price = 0

????????else

????????price *= value - 1

????????this.setState({price: price}) }

????render() {

????return (

????????{this.state.price}

)? }}

Item.js文件

import React, { Component } from 'react'

export default class Item extends Component {

????constructor(props) {

????????super(props)

????????this.handleChange = this.handleChange.bind(this)

????}

????handleChange(e){

????this.props.changePrice(e.target.value)

????}

????render() {

????????var options = []

????????var optionArray = this.props.optionArray

????????options = optionArray.map(function(item, index){

????????????return ( {item.name} )

????????})

????????return ( {options} )

????}

}

說明:

?1. 先綁定(bind)住render有用到的方法

在父組件與子組件各有用到一個(gè)自己的方法changePrice,并在render中作賦值,在React中需要bind過才會(huì)把this對(duì)住,因?yàn)樵趓ender的return語句中使用,它在重渲染(re-render)時(shí)會(huì)再次建立新的方法(函數(shù))內(nèi)容值,這樣會(huì)有效能上的影響,所以要先作綁定的事,然后再render的return里面用。關(guān)于bind(this)的一些理解,在我的另一篇文章,可以參考:http://www.itdecent.cn/p/f7f2636d16a9

先綁定要在類的contructor里作,像下面這樣,我這寫一個(gè)父組件而已,子組件一樣:

constructor(props) {super(props)this.state = {price:0}//先bind類中方法this.changePrice =this.changePrice.bind(this)? }

之后在render的return要改成這樣:

render() {return(

{this.state.price}

);? }


2. 校正state(狀態(tài))里的資料,以及提升到父組件去

在子組件中的state(狀態(tài))中的資料是不是有那么必要放在子組件中,如果你還有第二個(gè)子組件、第三、第四…,它們都要用例如這里的選中資料,你放在這個(gè)子組件是違反了上面說的應(yīng)用領(lǐng)域全局資料思維的。

先看一下子組件目前的state,是長(zhǎng)這個(gè)樣子:

this.state = {names: ['(1)免費(fèi)行李','2','3'],values: ['1','2','3'],selectName:'',prices:'0'}

這里要先校正一下,names與values是代表選項(xiàng)中的名與值,它們是有關(guān)聯(lián)的,所以應(yīng)該是這樣的下面結(jié)構(gòu)才是好些的,value如果是要用來代表數(shù)字,就用數(shù)字就行不需要用字串:

options: [? {name:'(1)免費(fèi)行李',value:1},? {name:'2',value:2},? {name:'3',value:3}]

選中了哪個(gè)選項(xiàng)這個(gè)狀態(tài)資料,還是要先放在子組件中,因?yàn)樽咏M件中有選項(xiàng)盒,與觸發(fā)的更動(dòng)方法,但選項(xiàng)的資料可以移到上層的父組件中:

這是上層App.js中的狀態(tài):

this.state = {options: [? ? ? ? {name:'(1)免費(fèi)行李',value:1},? ? ? ? {name:'2',value:2},? ? ? ? {name:'3',value:3}? ],price:0}

父組件也改用把state里面的選項(xiàng)值,用props值給子組件,所以在render里語句改成下面這樣:

render() {return(

{this.state.price}

)? }

子組件中這時(shí)可以用this.props.optionArray接到傳入的選項(xiàng)值,所以在render方法中,改用這個(gè)來代替之前的this.state.names與this.state.values,簡(jiǎn)單改寫如下:

varoptions = []varprices =this.state.pricesvaroptionArray =this.props.optionArrayfor(vari =0; i< optionArray.length; i++) {? ? ? options.push({optionArray[i].name})? }

注: 這里不用for...in語句而用for語句,是因?yàn)閒or...in語句是個(gè)不建議用在數(shù)組資料的語法,它并不會(huì)保證取到數(shù)組成員里的順序。for...in只會(huì)用在對(duì)象的尋遍中。

更精簡(jiǎn)的寫法是用Array.map,如下:

varoptions = []varprices =this.state.pricesvaroptionArray =this.props.optionArrayoptions = optionArray.map(function(item, index){return({item.name})})

接著,如果依選項(xiàng)選中然后計(jì)算價(jià)格這件事,規(guī)劃中應(yīng)該是整個(gè)應(yīng)用來作的,例如有可能還有其他的組件中也有其他的選項(xiàng),最后統(tǒng)一要來算價(jià)格,所以計(jì)算價(jià)格這件事,也應(yīng)該放到父組件去,所以如同上面的改寫一樣,把子組件的prices狀態(tài)與相關(guān)計(jì)算的代碼,都提到父組件,這個(gè)子組件純用來當(dāng)選項(xiàng)盒用而已。子組件此時(shí)連state都可以不用有。

因?yàn)檎麄€(gè)改寫過的代碼會(huì)多些,所以我把父組件與子組件中的代碼整個(gè)貼上。

父組件App.js:

importReact, { Component }from'react';importItemfrom'./Item'exportdefaultclassAppextendsComponent{constructor(props) {super(props)this.state = {options: [? ? ? ? {name:'(1)免費(fèi)行李',value:1},? ? ? ? {name:'2',value:2},? ? ? ? {name:'3',value:3}? ? ? ],price:0}this.changePrice =this.changePrice.bind(this)? }? changePrice(value){varprice =800;if(value ===1) price =0elseprice = (value -1) * pricethis.setState({price: price})? }? render() {return(

{this.state.price}

)? }}

子組件Item.js:

importReact, { Component }from'react'exportdefaultclassItemextendsComponent{constructor(props) {super(props)this.handleChange =this.handleChange.bind(this)? }? handleChange(e){this.props.changePrice(e.target.value)? }? render() {varoptions = []varoptionArray =this.props.optionArray? ? options = optionArray.map(function(item, index){return({item.name})? ? })return(

{options}

)? }}

3. 目前最終進(jìn)化版本

這個(gè)版本有幾個(gè)改進(jìn)如下,供參考:

用let/const取代var。

不用分號(hào)(;)作為語句結(jié)尾。

Item子組件改用函數(shù)定義方式,取代原先的組件定義方式。

能合并的語句都合并。

函數(shù)全用箭頭函數(shù)(注意需額外加裝babel-plugin-transform-class-properties)。

App.js

importReact, { Component }from'react'importItemfrom'./Item2'exportdefaultclassAppextendsComponent{constructor(props) {super(props)this.state = {options: [? ? ? ? {name:'(1)免費(fèi)行李',value:1},? ? ? ? {name:'2',value:2},? ? ? ? {name:'3',value:3}? ? ? ],price:0}? }? changePrice =(value) =>{letprice =800if(value ===1) price =0elseprice *= value -1this.setState({price: price})? }? render() {return(

{this.state.price}

)? }}

Item.js

importReactfrom'react'constItem =(props) =>{constoptionArray = props.optionArrayconstoptions = optionArray.map((item, index) =>{return({item.name})? })return(

{props.changePrice(e.target.value)}}>? ? ? ? ? ? {options}

)}exportdefaultItem



參考文檔: 1.?https://www.cnblogs.com/zhangbob/p/6962138.html?utm_source=itdadao&utm_medium=referral

2.?http://www.css88.com/react/docs/lifting-state-up.html官方文檔

3.https://blog.csdn.net/YQXLLWY/article/details/73481063

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容