iT邦幫忙

2

為何 React 官方推薦 setState 設定值而不使用 this.state設定?

挑戰 React 第十三篇

  • 上篇我們了解 state 可以在 component 裡改變資訊且實作。

  • 此篇將會用實作範例,證明修改 component 資料要用 setState 而不是使用 this.state 設定。

實作目標

按鈕按一下,數字增加 1

實作範例 - 使用 this.state 更新數字

  1. 新增一個 Counter.js 檔案

  2. 在 app.js 引入 counter.js

import React from 'react';
import './App.css';
import Counter from './Counter';

function App() {
  return (
    <div className="App">
      <Counter />
    </div>
  );
}

export default App;

  1. 設定 this.state 裡的 count 預設值為0
import React, { Component } from 'react'

class Counter extends Component {
  constructor(props) {
    super(props)
  
    this.state = {
       count: 0
    }
  }
  
  render() {
    return (
      <div>
        counter - {this.state.count}
      </div>
    )
  }
}

export default Counter
  1. 先 yarn start 第二步驟結果

確認 UI 取得 state 預設值 0

  1. 加入按鈕,按了按鈕 + 1
import React, { Component } from 'react'

class Counter extends Component {
  constructor(props) {
    super(props)
  
    this.state = {
       count: 0
    }
  }

  //用this.state設定數字增加 1 ,並用console.log檢查
  increment() {
    this.state.count = this.state.count + 1;
    console.log(this.state.count);
  }
  
  render() {
    return (
      <div>
        <div>counter - {this.state.count}</div>
        <button onClick={() => this.increment()}>button</button>
      </div>
    )
  }
}

export default Counter
  1. yarn start 第四步驟

console.log裡的數字確實有依照按鈕次數增加,但畫面上的數字仍然是0

用 this.state 設定後小結論

若直接用 this.state 設定值,UI 不會重新渲染,因此顯示的值一直是預設值 0。

實作範例 - 使用 setState 更新數字

上面的實作範例,已得知 this.state 直接設定不會重新渲染,我們要改用 setState 實作。

  1. 用 setState 更新數字
  increment() {
    this.setState({
       count: this.state.count + 1 
    })
    console.log(this.state.count);
  }
  1. yarn start 查看結果

修改寫法後,確實有依照按鈕按的次數更新數字

大家有發現 UI 的數字與 console.log 的數字不一致 ?

第一次按按鈕:
UI更新數字後為 1,但 console.log數字為 0

第二次按按鈕:
UI更新數字後為 2,但 console.log數字為 1

因為 setState 是非同步,而程式碼顯示的 console.log 數字為同步

  1. 用 callback value 查看狀況,便會了解為什麼數字不一致
increment() {
    this.setState({
       count: this.state.count + 1 
    },
    // callback,確認 this.setState 後的 this.state.count 有 +1
    () => {
        console.log('callback value', this.state.count)
    })
    // 因 setState 非同步,沒有立即取得更新後的值拿到預設值
    console.log(this.state.count);
  }

學習心得

一直到這篇學習,才了解 setState是非同步,而且從來沒有點擊過 setState 的說明寫法,若有興趣可查看以下程式碼:

setState<K extends keyof S>(
            state: ((prevState: Readonly<S>, props: Readonly<P>) => (Pick<S, K> | S | null)) | (Pick<S, K> | S | null),
            callback?: () => void
        ): void;

看完才了解原來 setState 可以用 callback,甚至還可以傳入參數,下篇會介紹 setState 容易踩雷的一個點以及如何用傳入的參數解決。


1 則留言

1

Chrome 的 console.log,有時候的確令人困惑 /images/emoticon/emoticon06.gif

感謝你的回覆~
console.log 在我這個菜鳥階段還是幫助很多,至少 debug 過程知道發生什麼事哈哈

我要留言

立即登入留言