【 React 】什麼是 React State

Jamie Lo
6 min readFeb 11, 2023

--

Photo by mostafa mahmoudi on Unsplash

本篇筆記摘錄自官方文件 State: A Component’s Memory

本篇將會開啟 React 的超級大重點 - 狀態 ( state )。

元件常常會需要為了回應使用者互動而改變畫面顯示。
就像是使用者在輸入框輸入內容時,我們必須要讓使用者知道自己輸入了什麼,或是在幻燈片上點擊下一頁的時候,裡面的照片應該要跳到下一頁,或是點擊購買時,要將產品放入購物車內。

元件會需要去記住這些事情:當前輸入值是什麼?現在的照片是哪一張?購物車裡面有哪些內容?

元件的記憶,稱為狀態。

When a regular variable isn’t enough

下方範例為一個用來渲染雕像照片的元件。

預期的功能為:點擊 Next 按鍵時,透過index1變為2,以此類推來更新照片內容。

但目前的寫法是沒有辦法如預期運作的,可以透過右方的輸出結果測試。

( 將左側拉桿向右移動,可以看見程式碼的部分,拉開後點擊左上角三條線漢堡圖示可以看見完整檔案,右邊則為輸出結果。 )

handleClick更新的是區域變數index,無法如預期運作的原因如下:

  1. 區域變數不會在渲染間持續存在,當 React 渲染元件第二次的時候,它會重新渲染,並不會去管區域變數有什麼改變。
  2. 改變區域變數不會觸發渲染,React 不會知道它需要再次渲染元件裡的新資料。

如果想要更新元件的資料,必須有以下兩個條件:

  1. 渲染間須保持資料的維持。
  2. 觸發 React 用新資料渲染元件 ( 重新渲染 )。

useStateHook 滿足了以上兩個條件:

  1. 狀態變數可以在渲染間持續存在。
  2. 狀態設置函式 ( setter function ) 可以更新變數,並且觸發重新渲染。

Adding a state variable

首先,為了加入狀態變數,必須在檔案的最上方匯入useState

import { useState } from ‘react’;

接下來,將原本的程式碼

let index = 0;

修改為

const [index, setIndex] = useState(0);

index為狀態變數,而setIndex為用來設置的函式 ( setter function )。

這邊的[]語法稱為陣列解構賦值 ( array destructuring ),這使我們可以從陣列中讀取值,使用useState時,這兩個項目都必須存在。

接下來我們來修改事件監聽器的內容:

function handleClick() {
setIndex(index + 1);
}

使用setIndex達成每次點擊時將index+ 1。

點擊輸出結果的 Next 按鍵,可以發現已經成功做出我們想要的效果:

Meet your first Hook

在 React 中,所有以use為命名開頭的函式皆被稱為 Hook,就像useState

Hooks 是一種特別的函式,它們只有在 React 渲染時可取得,使我們可以 “hook into” React 不同的功能,而狀態只是其中一種。

【 Pitfall 】

Hooks 只能在元件或是自定義 Hooks 中的最頂層被呼叫,不能在條件式、迴圈或其他巢狀函式中呼叫它。

Anatomy of useState

當我們呼叫useState,就是在告訴 React,希望這個元件記住某些事情:

const [index, setIndex] = useState(0);

在這個範例裡,我們希望 React 記住index

命名慣例: const [something, setSomething]

雖然也可以根據個人喜好命名,但依照命名慣例命名,可以讓整個專案更加容易被理解,提升程式碼的閱讀性。

useState中的唯一引數 ( argument ),就是狀態變數的初始值,在這個範例裡,我們將index的初始值設為0

const [index, setIndex] = useState(0);

元件每一次渲染時,useState都會給出一個包含兩個值的陣列:

  1. 我們所儲存的狀態變數。
  2. 可以更新狀態變數與觸發 React 再次渲染元件的設置函式。

以下為發生的順序:

  1. 元件第一次渲染的時候,由於我們將0傳入useState當作index的初始值,所以會 return[0, setIndex],React 會記住0是最新的狀態變數
  2. 更新狀態:
    當使用者點擊按鈕時,呼叫setIndex(index + 1)
    index0,所以會變成setIndex(1),這會告訴 React,現在的index1,並且觸發渲染。
  3. 元件第二次渲染,React 一樣會看見useState(0),但是 React 會記得我們把index設為1了,因此會 return[1, setIndex]
  4. 以此類推。

Giving a component multiple state variables

在同一個元件中,可以有多個不同類型的狀態變數。

以下方這個例子來說,Gallery元件擁有兩個狀態變數,數字類型的index與布林值showMore,請試著點擊 Show details 按鍵:

當狀態變數彼此互不相關,將它們分成不同的狀態變數是一個好的選擇,就像是範例中的indexshowMore,但當你發現兩個狀態變數常常一起改變時,那就適合將它們合併。

State is isolated and private

狀態是元件裡的區域實例 ( local instance ),換句話來說,如果我們渲染了同樣的元件兩次,兩個狀態是各自獨立的,改變其中一個並不會影響到另一個。

在這個範例裡,Gallery元件被渲染了兩次,但是點擊後可以發現,左側與右側的數字互不影響,互相獨立:

雖然我們渲染了兩次Gallery,但它們的狀態是分開儲存的。

這個範例還有一個值得注意的地方,Page元件不會知道Gallery元件的狀態,甚至不會知道它有沒有設置狀態,跟 props 不同,狀態在元件裡的宣告是完全私有的,父元件無法改變子元件的狀態,這個特性使得我們可以將狀態加入或移出元件,而不必擔心影響到其他元件。

如果希望兩個Gallery能夠同步它們的狀態,則需將狀態從子元件裡移除,並將狀態加到最靠近它們的共同父元件,使用方法將會在之後的筆記內提到,也可以先參照官方文件 Sharing State Between Components

--

--

Jamie Lo
Jamie Lo

Written by Jamie Lo

正在往前端這個知識量爆炸的黑洞前行,內容多為平時的筆記整理,希望也能幫助到同樣在這條道路上前進的人💪