logo

Mount PlaNet

instagram
2024-06-16 share
已複製文章連結

那些 React 你該知道的事:一般變數 vs. useRef vs. useState

Written by 雷卡



在程式中常會需要宣告變數來賦值或儲存值,變數主要分為兩種:

  1. 固定不變的常數(constant),如一個條件的上限數值,或是 function;
  2. 會改變的變數(variable),如用戶輸入表單的資訊,或者計時器上不斷更新的秒數。

在程式語言中,變數和一般數學定義有些不同,常數跟變數都稱為一種 variable。而現今 JavaScript ES6 版本,會推薦分別使用 const 及 let 來宣告變數(不要再用 var 了!),然而許多新手在剛接觸 React 的 function component 撰寫前端網頁時,可能都出現過這樣的疑問:

  • useState 好像也能做到,為什麼有時候要用 useRef?
  • 等等,那什麼時候又該單純地使用 const 或 let 呀?

一般變數宣告 - const vs. let


這兩個都屬於 block-scoped local variables,大部分情境使用 const 即可,能更好管理及維護程式並減少犯錯的機會,需要重新賦值時才使用 let。

  • const

    • 宣告常數
    • 初始宣告就要賦值
    • 不能重新賦值(can’t reassign)
    • 若型別為 object,雖無法賦予新的 object,仍可改變 properties
    • 對 array 來說也是一樣,可以透過 push 等方式 mutate
  • let

    • 宣告變數
    • 初始宣告可選擇性地賦值(不給值也 OK)
    • 能重新賦值(re-assignable)

當一般變數不夠用,你需要的是狀態變數 - useState


以簡單的計數器作為範例,每點一次 Count 按鈕,畫面上顯示的計次數量就會 + 1;因為 count 是會不斷增加、變動的值,所以用 let 來宣告計次的變數 count。

export default function Counter() {
  let count = 0;

  function handleClick() {
    count = count + 1;
  }

  return (
    <>
      <button onClick={handleClick}>Count</button>
      <span>點擊數量:{count} 次</span>
    </>
  );
}

實際去跑程式會發現畫面上的點擊數量根本不會動,為什麼呢?

  1. 一般變數無法在不同 render 間記住 value,每次 render 時都會重新宣告

    即使有 re-render,value + 1 後還是會再次被宣告為 0。(有人可能會說,那把 let 宣告在 component 之外就好啦,但當 Counter 不是 singleton 而是 multiple instances,components 之間就會共享到相同的變數了)

  2. 改變一般變數並不會觸發畫面重新渲染( won’t trigger renders)

值沒改變,畫面也未再次渲染,當然也就不會有什麼改變;這時候,就需要 useState 來新增 state variable 了,既能讓變數在不同 render 之間保留下來,還會觸發畫面 render!

useState is a React Hook that lets you add a state variable to your component.

-React


import { useState } from "react";

export default function Counter() {
  const [count, setCount] = useState(0);

  function handleClick() {
    setCount(count + 1);
  }

  return (
    <>
      <button onClick={handleClick}>Count</button>
      <span>點擊數量:{count} 次</span>
    </>
  );
}

若需保留變數,但不需要畫面重新渲染 - useRef


在剛剛的範例中,count 這個變數不只需要在不同 render 間保留,還需要觸發 render,因此需要使用 useState;但如果是需要保留變數,卻不需要重新渲染畫面的情境,可以使用 React 提供的另一個 hook:useRef

useRef is a React Hook that lets you reference a value that’s not needed for rendering.

-React


我曾遇過一種狀況,需要在 component 第一次 render 後不要執行 useEffect 內的 function,但往後的每次 render 都需要執行,於是我用 useRef 來記住是否已經 render 過第一次。

import { uesRef, useEffect } from "react";

export default function Counter() {
  const firstTimeRef = uesRef(false);

  useEffect(() => {
    if (!firstTimeRef.current) {
      firstTimeRef.current = true;
      return;
    }

    doSomething();
  });

  return <></>;
}

用來在 render 間記住、卻在改變時不需要觸發 render 的變數是 useRef 其中一種用法,此外它也很常用來操作 DOM,更多詳細資訊及用法可參考 React 官網介紹

最後,一次比較一般變數 vs. useRef vs. useState


變數種類constletuseRefuseState
常數 / 變數常數變數變數狀態變數
賦值不可重新賦值可重新賦值可重新賦值可透過 setState 重新賦值
render 之間重新宣告重新宣告記住 value記住 value
value 改變時不會觸發 render不會觸發 render觸發 render



References: