iT邦幫忙

2021 iThome 鐵人賽

DAY 22
0
自我挑戰組

Re: 從 Next.js 開始的 React 生活系列 第 22

[Day22] 在 Codecademy 學 React ~ 原來 useState 就是 this.state + this.setState 啊!

前言

其實你知道嗎?
今天要講的 this.state this.setState 其實就是之前介紹過的 useState 耶!!!!!!!!!!!!!!
有興趣的人可以右轉這兩篇看一下→
[Day14] 學 Reactstrap 就離 React 不遠了 ~ 用 Navbar 認識 useState
[Day15] 學 Reactstrap 就離 React 不遠了 ~ 用 Tooltips 熟悉 useState

但是學過 useState 的我回過頭去學 this.setState 反而覺得有點吃力orz
這樣我好難想像完全從零開始學 this.setState 的人會怎樣哦orz
那就正式開始吧! this.state

本日正文

this.state - 狀態

其實今天的語法我不曉得要怎麼講解比較好XD
雖然在 Codecademy 有一步一步做,
但是我到現在還是搞不太懂的語法 Codecademy 的說明我還是參不太透XD
所以我決定先把它當既定文法先記下來再說了XD
(用多次一點我搞不好就會突然頓悟了?)

先直接講結論好了,
不同於昨天講的 this.props
屬性只有在一開始 initial 或是在 component 被指定一次後就不能改變了,
this.state(狀態)的值是可以隨著與元件的互動改變的!
例如我今天天氣一開始很好,但後來天氣變差了,開始下雨。
上面這句話的敘述中,「天氣」就是一種狀態,而不是屬性。

然後在 React 要用 this.state 宣告狀態的語法是這樣的:

class Weather extends React.Component {
  constructor(props) {
    super(props);
    this.state = { weather: 'sunny' };
  }
}

完全看不懂 constructor(props)super(props) 是什麼XD
先當成文法背起來,
後面再補充說明XD

那我如果要在頁面上顯示我現在心情狀態該怎麼做?

跟昨天的 props 很像哦,
this.state.狀態 就可以取得上面所宣告的狀態:

render() {
    return (
      <h1>
        今天天氣:{this.state.weather}!
      </h1>
    );
  }

把全部程式放在昨天範例試試看吧!
在這邊新增一個 Weather.js,
宣告一個 Weather 的 component,
在裡面宣告 weather 的 state,
並在 render 渲染一個 <h1> 內容為 {this.state.weather}
像這樣:

import React from "react";

export class Weather extends React.Component {
  constructor(props) {
    super(props);
    this.state = { weather: 'sunny' };
  }
  render() {
    return <h1>今天天氣:{this.state.weather}!</h1>;
  }
}

然後在 App.js 引入 Weather.js 中的 Weather 的 component,
並在 <div></div> 放入 <Weather />
像這樣:

... (略)
import { Weather } from "./Weather.js";

export default function App() {
  return (
    <div className="App">
      ... (略)
      <Weather />
    </div>
  );
}

最後結果是:
https://ithelp.ithome.com.tw/upload/images/20210924/20129873hqBK24Ruu8.png

this.setState - 改變狀態

上面有提到狀態的值是可以隨著與元件的互動改變的!
所以這邊就開始要講如何改變狀態了,
首先我先在 Weather.js 天氣敘述下面放一個按鈕「改變天氣」,
打算讓它做的事就是按下去之後 sunny 跟 rainy 互換,
先宣告一個 <button>

render() {
    return (
      <div>
        <h1>今天天氣:{this.state.weather}!</h1>
        <button>改變天氣</button>
      </div>
    )
}

然後在 Weather.js constructor(props) {} 區塊外面,
下方插入以下程式:

changeWeather() {
    const newWeather = this.state.weather == 'sunny' ? 'rainy' : 'sunny';
    this.setState({ weather: newWeather });
  }

這邊的意思是宣告一個 function changeWeather,
裡面去判斷 weather 狀態是不是 sunny,是的話 newWeather 就被指定為 rainy,
不是的話 newWeather 就被指定為 sunny,
然後再將 weather 狀態的值改為 newWeather 的值。

然後又有我不懂的語法了XD
一樣先照抄,
這次要在 constructor(props) {} 區塊裡面,
this.state = { weather: "sunny" }; 下方插入以下程式:

this.changeWeather = this.changeWeather.bind(this);

到這邊只是把天氣狀態跟改變天氣狀態宣告好而已,
還差一步,
就是要把按鈕的 onClick 綁成改變天氣狀態的 function,
像這樣:

<button onClick={this.changeWeather}>改變天氣</button>

最後 Weather.js 的程式全部會長這樣:

import React from "react";

export class Weather extends React.Component {
  constructor(props) {
    super(props);
    this.state = { weather: "sunny" };
    this.changeWeather = this.changeWeather.bind(this);
  }

  changeWeather() {
    const newWeather = this.state.weather == 'sunny' ? 'rainy' : 'sunny';
    this.setState({ weather: newWeather });
  }

  render() {
    return (
      <div>
        <h1>今天天氣:{this.state.weather}!</h1>
        <button onClick={this.changeWeather}>改變天氣</button>
      </div>
    );
  }
}

讓我們看一下執行結果:

this.state + this.setState = useState

所以這邊兜回去文章前言一下,
有沒有覺得今天講的這一段

constructor(props) {
    super(props);
    this.state = { weather: "sunny" };
    this.changeWeather = this.changeWeather.bind(this);
  }

  changeWeather() {
    const newWeather = this.state.weather == 'sunny' ? 'rainy' : 'sunny';
    this.setState({ weather: newWeather });
  }

整個意思長得很像之前所用的 useStatesetXXX 呢?
useState 可以改寫成這樣:

const [weather, setWeather] = useState('sunny');
setWeather('rainy');

其實這根本就是前面那一段的綜合體吧XD
這邊也可以參考之前大大在鐵人賽文章的說明→ 【React.js入門 - 13】 useState - 在function component用state

為什麼有 constructor(props) 啊?

現在回過頭看一下不懂的語法好了XD
constructor 牽扯到 React 的 LifeCycle (生命週期),
https://ithelp.ithome.com.tw/upload/images/20210924/20129873nCdepXdc8v.png
可以看一下這張生命週期圖,
constructor 落在 render 之前,
所以我個人的解讀是在正式渲染元件到 DOM 之前,
要先把會用到的 props, state 等建置起來。

這邊還有一篇大大寫的文章 [第二十一週] React 生命週期: 建立初期 constructor、componentDidMount
但我還沒上到 LifeCycle (生命週期) 章節,
所以這篇文章我還看不懂XD

為什麼又有 super(props) 啊?

再來 super(props) 又是什麼XD
可以參考大大寫的這篇文章:為什麼我們要寫 super(props) ?

在 JavaScript 中,super 會參照父類別的建構子。(在我們的例子當中,它會指向 React.Component 的實作。)

https://ithelp.ithome.com.tw/upload/images/20210924/20129873TnTvZH5Ipz.png

剩下的我也還在參透,
總之就是用了 super(props) 才能在下面語法使用 this ~

為什麼還要 bind 啊?

來到最後一個世紀謎題(?)

this.changeWeather = this.changeWeather.bind(this);

就是為什麼 this.changeWeather 還要 bind(this)

這邊就直接把 bind 那一行程式註解掉再執行看看會發生什麼事吧!
https://ithelp.ithome.com.tw/upload/images/20210924/20129873N1eew7XOfQ.png

可以發現直接出錯,錯誤訊息是

Cannot read properties of undefined (reading 'state')

哦,好像大概知道了,
weather 這個 state 被宣告在 constructor 裡面,
在 constructor 外面的 changeWeather() 是不認得 this.state.weather 的,

this.changeWeather = this.changeWeather.bind(this);

所以這邊有點是要建立 this.changeWeather 跟 constructor 裡面 state 的橋樑的感覺(?)
這邊看了幾篇文章覺得還是沒有參得很透,
我目前是先這樣想啦XD

可以參考的文章們:
React 與 bind this 的一些心得
Handling Events(官方文件)

參考官方文件說:

// This binding is necessary to make this work in the callback
this.handleClick = this.handleClick.bind(this);

但我還是參不透XD

總之這篇文章大大有提到,

而當有了 Hooks 後,我們甚至不需要 super 或是 this。

XD
而之前學的 useState useEffect 好像都是 Hook 的一種XD
在官方文件 使用 State Hook 中,
提到:

Hook 是 React 16.8 中增加的新功能。它讓你不必寫 class 就能使用 state 以及其他 React 的功能。

哦~這也就難怪我之前寫的語法貌似比較簡單XD
所以我決定放棄研究 constructor super bind this
好啦,我覺得大概知道它用法就好,
至少之後在網路上看範例時知道它是做什麼的就好XD

不然我記得我之前在範例程式只要一看到以下這段我就會立馬把那個頁面關掉XD
至少現在我能面對它了(?)

constructor(props) {
    super(props);
    this.state = { weather: "sunny" };
    this.changeWeather = this.changeWeather.bind(this);
  }

然後一樣附上今日程式→ Day22 - this.state & this.setState(Codecademy)

後記

看了一下 Codecademy,
後面要進入 React LifeCycle (生命週期) 了耶XD
希望看了之後可以參透今天不懂的這些地方XD


上一篇
[Day21] 在 Codecademy 學 React ~ What's this? This is "this"! 之 this.props 篇
下一篇
[Day23] 在 Codecademy 學 React ~ Component Lifecycle 生命週期我不懂你QQ
系列文
Re: 從 Next.js 開始的 React 生活30

尚未有邦友留言

立即登入留言