在第0篇有提到state在React的重要性:
state 是用來驅動component更新(re-evaluate),並且根據修改的地方重新渲染(re-render)畫面。
在正式說明state之前,有個關於function component的重要性質必須提及:
重新渲染(re-render)畫面,代表重新呼叫(call)function component,所以component裡面的變數等都會重新建立
從JavaScript語法的角度試想一下,每次呼叫函式(function),函式內變數若沒有特別設計(如用閉包(Closure)保存一個區域變數的值),函式內變數的生命週期都會在函式結束呼叫後消失,並在函式呼叫時重新建立。
如下範例(live demo)即便使用 counter++;
,但因為變數 counter
的生命週期會在函式結束時消失,不管呼叫多少次 sayHello();
仍然會得到 counter
為 1,而不是加總多次的 counter
變數值。
function sayHello(){
let counter = 0;
counter++;
return counter;
}
sayHello();
sayHello();
sayHello();
console.log(sayHello()); // 1
同理,一般變數在React的function component在沒有特地保存的情況下,也會在畫面重新渲染(函式重新呼叫)時消失。
為了保存函式內某些變數的值(或者有時會稱「要保存某些變數的狀態」),state 另一個重要用途就是保存(preserve) function component裡的值。
若要在function component使用state,必須用React hooks其中的 useState
,使用方式如下:
- 引入模組
import {useState} from 'react';
- 宣告React state變數
const [state, setState] = useState(0);
- useState() 指的是要使用 useState 這個 Hook,
useState()
括號裡面是state變數的初始值,可以是0
、[]
、""
、{}
等,而useState會回傳一個陣列,包含目前的狀態 state 和可以用來改變狀態的 setState函式,可以用陣列解構(destructure)的方式取得: - state 是state變數名稱,也就是目前變數值或狀態
- setState 是可以改變 state變數值的函式,慣例會以 set 加上
- useState() 指的是要使用 useState 這個 Hook,
完整的使用方式可以參考live demo 或以下簡化live demo範例後的程式碼。
// 以下是Demo範例簡化後的程式碼
import { useState } from 'react';
export default function Counter(){
const [count, setCount] = useState(0); // React's state variable
let counter = 0;
return(
<div>
<p>counter: {counter}</p>
<p>count: {count}</p>
<button onClick={()=>counter++}>Add counter First</button>
<button onClick={()=>setCount(count+1)}>Add count Second</button>
</div>
);
}
程式碼參考React文件設計兩個計數器,這裡刻意放了一個純JavaScript的函式內區域變數 counter
來比較 React 的 useState
變數 count
。改變計數器狀態的方式是在button標籤裡面新增一個onClick事件,並且用匿名函式包裝一下 counter++
,以及用callback函式去呼叫 setCount(count+1)
(不能直接使用onClick = setCount(count+1)
會變成是直接呼叫setCount函式)
從 live demo 應該可以發現 counter
無法直接對他做改變,這裡我是理解成 counter
的生命週期會在函式結束時消失,所以沒辦法改變它。
而 React 則在 setCount(count+1)
之後,會改變 count
這個 state 的值,並且 re-render Counter component,然後將新的 count
值呈現在畫面上。
統整官方文件和範例結果的一些重點:
- Function component 裡面沒有 this,如果要保存 React function component 內的變數值或狀態需要用
useState
(事實上也有其他的hooks可以保存變數狀態,但目前只介紹到useState);假設是用一般函式內的區域變數
(例如範例的counter
),不僅變數值會消失,也無法改變變數值。 - 使用
useState
的方式是先引入模組,然後宣告 state 變數 (state
)、改變 state值的函式(setState
),在useState()
括號內初始化 state 變數的初始值,如:
const [state, setState] = useState(/* initial value */);
- 改變state變數值時會連帶 re-render component,而React的useState不管是經過多少次的re-renders都可幫我們保存這些state變數值
- useState可以用陣列(Array)或物件(Objact)變數,所以如果要保存有高度關聯性的變數值,可以善用陣列或物件,而不是宣告一堆state變數。
- 最後React官方文件有提到: state updates may be asynchronous,大意是,基於效能上的考量,React設計成會先知道有哪些states用
setState()
更新,並在下次渲染一次更新所有states;因此,使用setState()
並非是立即更新state,如果需要取用前一次的state,則要在setState()
內寫成function形式,並用funciton接收前一次狀態的參數來處理,如範例的prevState
:setState( prevState => prevState + updatedValue );
- 由此可知,
setState
的作用是:(1) 更新state (2) 告訴React要在下次畫面渲染更新指定的state
另外,如果component裡面有用 useState
hook 管理狀態,稱這個component為 controlled component 或是 statefull/smart component;相反地,component裡面沒有管理state,則稱這種類型的components為 uncontrolled components 或是stateless/dumb/presentational components
最後題外話一下,從useState來看Hooks,Hooks 有點像是幫忙在函式內 勾 住想保留的東西?🤔
References