點燈坊

戦わなければ、勝てない

如何使用 useState() Toggle State ?

Sam Xiao's Avatar 2019-09-29

JSX 若要根據 State 做不同的顯示,當然可以將 JavaScript 直接寫在 JSX 內,但比較好的方式是抽成 Method 或 Function,如此可避免 JSX 內 HTML 與 JavaScript 混在一起的 Spaghetti Code。

Version

macOS Mojave 10.14.6
WebStorm 2019.2.3
Node 12.11.0
Yarn 1.19.0
create-react-app 3.1.2
React 16.10.1

Class Component

import React, { Component } from 'react';

export default class extends Component {
  state = {
    isOn: true,
  };

  toggleState = () => {
    this.setState(prevState => ({ isOn: !prevState.isOn }));
  };

  showTitle = () => this.state.isOn ? '+' : '-';

  render() {
    return (
      <div>
        <button onClick={ this.toggleState }>Toggle</button>
        <div>{ this.showTitle() }</div>
      </div>
    );
  }
}

第 4 行

state = {
  isOn: true,
};

定義 isOn state,其初始值為 true,將來會 toggle 此值。

第 8 行

toggleState = () => {
  this.setState(prevState => ({ isOn: !prevState.isOn }));
};

使用 setState() 更改 state,其中 prevState argument 回傳回前一次的 state,藉由 !prevState.isOn 可 toggle state。

14 行

render() {
  return (
    <div>
      <button onClick={ this.toggleState }>Toggle</button>
      <div>{ this.showTitle() }</div>
     </div>
  );
}

render() 負責 return JSX,其中 <div> 會根據 isOn state 有不同的結果,當然可以直接寫在 JSX 內,但這樣 JavaScript 邏輯與 JSX 混雜不易閱讀,比較好的方式是抽成 showTitle() method。

12 行

showTitle = () => this.state.isOn ? '+' : '-';

根據 isOn state 結果顯示 +-

Function Component

import React, { useState } from 'react';

export default () => {
  let [isOn, setIsOn] = useState(true);

  let toggleState = () => setIsOn(prevState => !prevState);

  let showTitle = () => isOn ? '+' : '-';

  return (
    <div>
      <button onClick={ toggleState }>Toggle</button>
      <div>{ showTitle() }</div>
    </div>
  );
};

第 4 行

let [isOn, setIsOn] = useState(true);

使用 useState() 建立 isOn state 與 setIsOn() setter,並直接傳入初始值 true

第 6 行

let toggleState = () => setIsOn(prevState => !prevState);

定義 toggleState(),使用 setIsOn() setter 設定 isOn state,直接使用 !prevState argument 做 toggle。

10 行

return (
  <div>
    <button onClick={ toggleState }>Toggle</button>
    <div>{ showTitle() }</div>
  </div>
);

直接 return JSX,其中 <div> 會根據 isOn state 有不同的結果,當然可以直接寫在 JSX 內,但這樣 JavaScript 邏輯與 JSX 混雜不易閱讀,比較好的方式是抽成 showTitle()

第 8 行

let showTitle = () => isOn ? '+' : '-';

定義 showTitile(),根據 isOn state 顯示 +-

Conclusion

  • 與 counter 不同的是本範例在 JSX 會根據 isOn state 結果做不同顯示,傳統對 JSX 的批評大都是 JavaScript 與 HTML 混在一起,造成所謂 spaghetti code,但事實上無論 class component 或 function component,顯示邏輯都可抽成 method 或 function,因此 JSX 只要 coding style 好,就不會有維護問題

Reference

Reed Barger, Toggle State with useState