官术网_书友最值得收藏!

2.2.2 React的state

驅動組件渲染過程的除了prop,還有state, state代表組件的內部狀態(tài)。由于React組件不能修改傳入的prop,所以需要記錄自身數據變化,就要使用state。

在Counter組件中,最初顯示初始計數,可以通過initValue這個prop來定制,在Counter已經被顯示之后,用戶會點擊“+”和“-”按鈕改變這個計數,這個變化的數據就要Counter組件自己通過state來存儲了。

1.初始化state

通常在組件類的構造函數結尾處初始化state,在Counter構造函數中,通過對this. state的賦值完成了對組件state的初始化,代碼如下:

constructor(props) {
  ...
  this.state = {
    count: props.initValue || 0
  }
}

因為initValue是一個可選的props,要考慮到父組件沒有指定這個props值的情況,我們優(yōu)先使用傳入屬性的initValue,如果沒有,就使用默認值0。

組件的state必須是一個JavaScript對象,不能是string或者number這樣的簡單數據類型,即使我們需要存儲的只是一個數字類型的數據,也只能把它存作state某個字段對應的值,Counter組件里,我們的唯一數據就存在count字段里。

注意

在React創(chuàng)建之初,使用的是React.createClass方法創(chuàng)建組件類,這種方式下,通過定義組件類的一個getInitialState方法來獲取初始state值,但是這種做法已經被廢棄了,我們現在都用ES6的語法定義組件類,所以不再考慮定義getInitialState方法。

由于在PropType聲明中沒有用isRequired要求必須有值的prop,例如上面的initValue,我們需要在代碼中判斷所給prop值是否存在,如果不存在,就給一個默認的初始值。不過,讓這樣的判斷邏輯充斥在我們組件的構造函數之中并不是一件美觀的事情,而且容易有遺漏。我們可以用React的defaultProps功能,讓代碼更加容易讀懂。

給Counter組件添加defaultProps的代碼如下:

Counter.defaultProps = {
  initValue: 0
};

有了這樣的設定,Counter構造函數中的this.state初始化中可以省去判斷條件,可以認為代碼執(zhí)行到這里,必有initValue屬性值,代碼可以簡化為這樣:

this.state = {
  count: props.initValue
}

以后,即使Counter的使用者沒有指定initValue,在組件中就會收到一個默認的屬性值0。

2.讀取和更新state

通過給button的onClick屬性掛載點擊事件處理函數,我們可以改變組件的state,以點擊“+”按鈕的響應函數為例,代碼如下:

onClickIncrementButton() {
  this.setState({count: this.state.count + 1});
}

在代碼中,通過this.state可以讀取到組件的當前state。值得注意的是,我們改變組件state必須要使用this.setState函數,而不能直接去修改this.state。如果不相信,你可以嘗試把onClickIncrementButton函數修改成下面的樣子:

onClickIncrementButton() {
  this.state.count = this.state.count + 1;
}

既然this.state就是一個JavaScript對象,上面的代碼邏輯看起來也沒有什么問題,我們在界面上點擊幾個按鈕看一下實際效果就會發(fā)現問題。

首先,在瀏覽器的Console中會有如下的提示:

warning Do not mutate state directly. Use setState() react/no-direct-mutation-state

這是在警告:“不要直接修改state,應該使用setState()。”

當你點擊“+”按鈕,也不會看到后面的計數值有任何變化,但是當你點擊“-”按鈕,就會立即看到計數值發(fā)生變化,而且計數值會發(fā)生“跳躍”,比如在初始計數值為0的情況下,連續(xù)點擊“+”按鈕三次,計數值沒有任何變化依然為0,點擊了一下“-”按鈕一次,就會看到計數值一下子變成了2,這是怎么回事?

直接修改this.state的值,雖然事實上改變了組件的內部狀態(tài),但只是野蠻地修改了state,卻沒有驅動組件進行重新渲染,既然組件沒有重新渲染,當然不會反應this.state值的變化;而this.setState()函數所做的事情,首先是改變this.state的值,然后驅動組件經歷更新過程,這樣才有機會讓this.state里新的值出現在界面上。

在上面描述的操作中,連續(xù)點擊三次“+”按鈕,this.state中的count字段值已經被增加到了3,但是沒有重新渲染,這時候點擊一次“-”按鈕,觸發(fā)的onClick-DecrementButton函數依然是用this.setState改變組件狀態(tài),這個函數調用首先把this.state中的count值從3減少為2,然后觸發(fā)重新渲染,于是我們看到界面上的數字一下子從0跳躍為2。

主站蜘蛛池模板: 牡丹江市| 广宁县| 吴桥县| 绍兴县| 威信县| 昆明市| 合川市| 本溪| 石嘴山市| 安顺市| 武鸣县| 通山县| 濉溪县| 温宿县| 洪江市| 德安县| 石棉县| 闵行区| 普定县| 清水河县| 合作市| 德钦县| 名山县| 瑞安市| 明星| 凤凰县| 五家渠市| 九寨沟县| 饶河县| 康马县| 乐亭县| 固阳县| 贺州市| 土默特左旗| 晴隆县| 任丘市| 锡林郭勒盟| 彰化市| 十堰市| 敦煌市| 通化县|