今天要來學習state的應用,內容包含:
state,字面上的意思就是當前的程式狀態,我們也可以試著用生活中的例子來理解,譬如我們買了一杯咖啡,咖啡是「熱的」,「熱的」就是一種state,假設過了一小時咖啡冷了,「冷的」也會是一種state,而在「熱的」和「冷的」之間也存在著許多其他的state(漸漸變冷的狀態間),而在程式中,state是由行的程式操作和反映的數據。
import { sculptureList } from './data.js';
export default function Gallery() {
let index = 0;
function handleClick() {
index = index + 1;
}
let sculpture = sculptureList[index];
return (
<>
<button onClick={handleClick}>
Next
</button>
<h2>
<i>{sculpture.name} </i>
by {sculpture.artist}
</h2>
<h3>
({index + 1} of {sculptureList.length})
</h3>
<img
src={sculpture.url}
alt={sculpture.alt}
/>
<p>
{sculpture.description}
</p>
</>
);
}
這是一個Gallery 的元件,當中含有處理「下一張」的按鈕,透過起始值設定為0,並試圖用 index = index + 1;
來達到跳轉到下一張的功能。但這個並沒有辦法運作,原因是因為
React 元件中定義的變數,通常用於在渲染過程中儲存或處理數據。這些變數僅在函數的執行期間存在,並且在每次組件重新渲染時都會重新創建。因此,它們不會在不同渲染之間保留任何狀態。
React 不會自動監聽本地變數的更改並觸發元件的重新渲染。這意味著,即使在渲染函數中修改了本地變數的值,React 也不會意識到這些更改,並不會導致元件再次渲染。(底下補充:React的渲染機制)
好的,所以我們要解決的事情有二:儲存資料以及觸發渲染,而在React當中我們可以透過useState
來處理這些事情。
我們可以透過以下的三個步驟來使用useState
import { useState } from 'react';
const [index, setIndex] = useState(0);
這是解構賦值的應用。
在這邊我們創建了名為index的狀態變數,並設定起始值為0
function handleClick() {
setIndex(index + 1);
}
如同下面的結果:
import { useState } from 'react';
import { sculptureList } from './data.js';
export default function Gallery() {
const [index, setIndex] = useState(0);
function handleClick() {
setIndex(index + 1);
}
let sculpture = sculptureList[index];
return (
<>
<button onClick={handleClick}>
Next
</button>
<h2>
<i>{sculpture.name} </i>
by {sculpture.artist}
</h2>
<h3>
({index + 1} of {sculptureList.length})
</h3>
<img
src={sculpture.url}
alt={sculpture.alt}
/>
<p>
{sculpture.description}
</p>
</>
);
}
這樣子「next」按鈕就可以正常運作了。
這邊我們使用的是import,我們也可以使用另一種不使用import的方法來編寫
const [count, setCount] = React.useState(0);
這樣子的寫法則不需要使用import,二種方法也是相等的。
我們剛剛使用的useState
也可以說是React hook的一種,在React當中以‘’use’’開頭的function稱為Hook,Hook是一種特殊的function,它只在渲染當中運作,而且它只能在元件中的最高層級被呼叫,沒辦法在loops或是巢狀的function當中使用,使用 useState
、useEffect
或其他 Hooks 時,它們應該始終存在於組件中,而不受條件語句或其他邏輯的影響。關於Hook後續的文章會再更詳細介紹。
useState
Hook當中有什麼呢?
useState
Hook回傳的array有二個東西。
而這二者的命名其實不限,就算使用
const [hello, world] = React.useState(0);
這樣其實也是能運作的,但命名上約定成俗的命名概念是
const [something, setSomething]
再次注意,useState
接受的是一個參數,也就是初始值。
我們也可以視情況所需同時運用一個以上的狀態變數:
import { useState } from 'react';
import { sculptureList } from './data.js';
export default function Gallery() {
const [index, setIndex] = useState(0);
const [showMore, setShowMore] = useState(false);
//第一個處理「下一張」的點擊按鈕funciton:+1
function handleNextClick() {
setIndex(index + 1);
}
//第二個處理「顯示更多資訊」的點擊按鈕function:布林值
function handleMoreClick() {
setShowMore(!showMore);
}
let sculpture = sculptureList[index];
return (
<>
<button onClick={handleNextClick}>
Next
</button>
<h2>
<i>{sculpture.name} </i>
by {sculpture.artist}
</h2>
<h3>
({index + 1} of {sculptureList.length})
</h3>
<button onClick={handleMoreClick}>
{showMore ? 'Hide' : 'Show'} details
</button>
{showMore && <p>{sculpture.description}</p>}
<img
src={sculpture.url}
alt={sculpture.alt}
/>
</>
);
}
當二個狀態彼此的關係不相關,可以透過複數個狀態變數來控制,然而當狀態彼此之間有其關連性經常連動性調整時,應該將其合而為一。
state是獨立且私有的(isolated and private),也就是說當你渲染了同一個元件二次,二者會有完全獨立的state,就算更動其中之一,也不會影響另一方。
React 的渲染機制:當 React 重新渲染一個元件時,它會將該元件的整個渲染函數重新執行一次,然後將新生成的 JSX 與之前的版本進行比較,以確定需要更新的部分。