iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 5
1
Modern Web

React + D3 的正確姿勢系列 第 5

Day05-state and props

前言

今天要來談一談 React 是如何更新 component ,今天的文章會跟昨天講到的 component life cycle 息息相關,假如讀者對 component life cycle 有任何不懂的一定要先回昨天的文章複習一下,這樣才比較容易理解今天的文章喔!

state

state 簡單來說就是元件的狀態,只要元件的狀態改變就一定會觸發 render() ,而 state 永遠都會是一個物件,定義 state 的方式也非常簡單,只要在 class 內設定一個變數叫 state 之後就可以透過 this.state 的方式來進行 state 的呼叫了。

class App extends Component {
  state = { name: 'Andy' }
  
  render() {
    const { name } = this.state
    return <h1>Hello {name}</h1>
  }
}

知道怎麼呼叫 state 後接下來講講如何更新 state 來達到元件的更新, React 提供了一個叫 setState() 的方法來改變 state ,而 setState() 必須要透過 this.setState() 的方式來呼叫,一般來說 setState() 會有兩種寫法,一種是直接回傳一個 新的物件 另一種是透過 callback 來回傳一個 新的物件 ,寫法如下:

class App extends Component {
  state = { name: '' }
  
  componentDidMount() {
    // 直接回傳物件
    this.setState({ name: 'Andy' })
    // 利用 callback 方式回傳物件,callback 可以帶入目前的 state 來進行更彈性的改寫
    this.setState(state => ({ state: `${state.name} Chen` }))
  }
  
  render() {
    const { name } = this.state
    return <h1>Hello {name}</h1>
  }
}

這邊筆者要做個小提醒, state 的改寫一定要回傳一個 新的物件 ,所以在利用 callback 的方式來進行 state 的改寫時,一定要特別注意到 JS 對於物件拷貝的陷阱,如果對於 JS 的物件拷貝有任何不懂的歡迎參考筆者之前寫過的文章。

關於JS中的淺拷貝(shallow copy)以及深拷貝(deep copy)

props

props 其實非常好懂,讀者可以把 props 想像成 parameters ,由於 JSX 的寫法就跟一般的 HTML 沒兩樣,所以簡單來說只要是寫在 attribute 的都叫做 props ,這邊用個簡單的範例碼來示範一下 props

class Welcome extends Component {
  render() {
    const { name } = this.props
    return <h1>Hello! {name}</h1>
  }
}

class App extends Component {
  render() {
    return (
      <Welcome name={'Andy'} />
    )
  }
}

先來講一下上面程式碼的流程,有一個 containerApp ,這個 containerrender 這個函式呼叫了 Welcome 這個 component ,並且把 name={'Andy'} 傳進去 Welcome 裡,而 props 指的就是 name={'Andy'} ,在傳遞的過程中 React 會把這些 props 集中起來用一個叫做 props 的物件來儲存,所以負責接收 propscomponent 就可以利用 this.props 的方式來獲得 props 了,完整的範例碼可以參考下方的連結。

simple components-and-props

與 life cycle 的搭配

最後來講一下 life cyclestate 的搭配:

  • mounting

    • componentDidMount()

      其實筆者是不建議在 componentDidMount 進行 state 的改寫,這樣的做法就等於是立馬進行重繪的動作,要知道操作 DOM 是一件成本非常高的事情,所以要盡量避免在 componentDidMount 裡面 setState ,然而有些情況還是必須得這麼做才行,像是時間的更新等等這種就不能避免了,但平常在撰寫的時候還是建議不要在 componentDidMount 裡面進行 state 的改寫喔!

    • render()

      讀者們一定要記住一件事情,千萬不能在 render() 內進行 setState 否則一定會變成無窮迴圈,其實原因很簡單: render() 是代表元件內的元素正在繪製中,假如我們在繪製的過程中觸發了 state 的改變,這時候 React 又會再重新呼叫一次 render() ,所以元素就永遠沒有繪製完畢的一天,之後網頁就會 crash 了,至於在 componentDidMount 裡面寫 setState 不會出錯的原因是因為這時候已經是進入 updating 的過程了,所以就不會再進入 componentDidMount 了。

  • updating

    • shouldComponentUpdate(nextProps, nextState)

      就如上面文章所說,元件是否需要更新畫面取決於 state 是否更新,在昨天的文章有提到在 updating 的過程中,有些 updating function 可以帶入 nextStateprevState ,這時候就可以藉由比較新的 state 以及舊的 state 來決定是否需要進行元件的畫面更新,例如有些確定不會一直更新畫面的元件就可以透過 shouldComponentUpdate(nextProps, nextState) 保證元件不會進入 render() 內進而達到效能的提升,不過 React 也知道這件事情,所以也特別為了這段過程寫了一個 component ,至於是什麼 component 呢?明天筆者就會揭曉瞜!

最後筆者在這邊附上與 life cycle 搭配後的範例碼,歡迎大家點連結進去操作看看!

simple-clock

總結

今天講了 React 是如何透過 state 來進行畫面的重繪,其實掌握好這點 React 基本上就學的差不多了,剩下的都只是一些更深入的內容,如果有什麼問題歡迎在下方留言給我,沒問題明天就要開始講 React 中更進階的 component


上一篇
Day04-React components
下一篇
Day06-React元件比較
系列文
React + D3 的正確姿勢30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言