內容目錄
Toggle前言
前一篇則針對 React 語法進一步做講解, React 生命週期 – React 白話文運動 10 學會了 React 生命週期三個階段,並且學會了類別物件、函式物件的生命週期。這一篇則用實例來解說 Hook 中的 useState:
- useState 是什麼?
- 建立一個評價的 UI 元件
- 針對此元件進行重構
- 為此元件加上 useState 的 hook
- 新增 setState 為評價元件新增修改功能
- 舊版的 React 狀態管理寫法
useState 是什麼?
useState 是 React 中的一個 Hook,用於在函式元件中添加狀態,透過 useState,我們可以在函式元件中定義和管理狀態資料。
useState 返回一個包含兩個值的陣列,其中包括:
- 當前的狀態:在元件首次渲染時,它的值將等同於我們傳遞給 useState 的初始值。
- set 函式:這個函式負責更新狀態的值,同時觸發元件的重新渲染。
const [state, setState] = useState(initialState)
建立一個評價的UI元件
這邊使用 Alex Banks & Eve Porcello 所出的 React 教學來做講解,不過其中一些程式碼有稍作修改。
因為這一篇文章要建立一個 UI 頁面,因此需要使用 react-icons 套件,裡面有內建數百個 SVG 的圖庫。我們可以在 terminal 輸入以下的指令,即可下載 react-icons 套件。
npm i react-icons
透過 建立React專案 – React 白話文運動 08 的教學步驟,快速建立一個 react 專案。
npx create-react-app my-app
cd my-app
npm start
這時候就會在本地端啟動一個 react 專案,接下來修改一下 App.js 如以下,便可以獲得以下的 UI 元件。
import React from 'react'
import { FaStar } from 'react-icons/fa'
export default function App() {
return (
)
}
針對此元件進行重構
重構(refactor)的意思是指:在不改變程式結果的同時,改寫程式碼,讓整體程式碼品質提升。
接下來我們要根據原有的程式碼進行重構,讓整體程式碼變得更簡潔。這裡可以分成三個部分做講解:
重構第一步
可以先把 FaStar 拆成獨立的元件,並且針對這個元件給予參數,這邊給予的參數為 selected 引數,預設值為 true。
const Star = ({ selected = true }) => (
)
重構第二步
建立一個函數,只要給予長度,就可以快速組合出一個陣列。
const createArray = length => [...Array(length)];
重構第三步
最後在使用的 UI 裡面,使用 ES6 陣列的 map,在 map 函式中會回傳對應的 index 以及元件。
export default function App({ totalStar = 5 }) {
return createArray(totalStar).map((n, i) => )
}
當完成重構後,原本的程式執行結果是不變的,最後依然會回傳五個星星。
import React from 'react'
import { useState } from 'react';
import { FaStar } from 'react-icons/fa'
const Star = ({ selected = true }) => (
)
const createArray = length => [...Array(length)];
export default function App({ totalStar = 5 }) {
const [selectedStars] = useState(3)
return createArray(totalStar).map((n, i) =>
i} />)
}
為此元件加上 useState 的 hook
重構後的程式碼,尚未加上任何相關的資料或是狀態。這邊我們可以針對函式元件,使用一些 hook 來進行狀態管理。
useState( ) 就是我們在學習 hook 中第一個會學習到的函式,我們可以透過以下語法,給予一個元件的狀態 。
const [variable,setVariable] = useState("");
以下列程式碼的例子來說,我們給 App 這個函式元件新增了一種狀態,稱為 selctedStars。並且設定值 selctedStars 為 3,那在這個元件中,我們就可以針對這個變數去做對應的渲染。
import React from 'react'
import { useState } from 'react';
import { FaStar } from 'react-icons/fa'
const Star = ({ selected = true }) => (
)
const createArray = length => [...Array(length)];
export default function App({ totalStar = 5 }) {
const [selectedStars] = useState(3)
return createArray(totalStar).map((n, i) => i} />)
}
因為設定了 selctedStars 為 3,並且也在 FaStar 元件中設定了判別式。如果 selected 是 true 則顯示紅色,否則顯示黑色,最後就會有以下元件。
setState 新增修改功能
useState( ) 除了可以給予預設值以外,也可以修改其值,這邊可以使用 setState來去做修改。
可以在 StarRating 中,新增一個 setSelectedStars,就可以在元件中做使用。這邊也在 Star 裡面新增一個函數引數,稱為 onSelect ,並且將 setSelectedStars 傳進去。
export function StarRating({ totalStars = 5 }) {
const [selectedStars, setSelectedStars] = useState(3)
return
{createArray(totalStars).map((n, i) =>
i}
onSelect={() => setSelectedStars(i + 1)} />
)}
{selectedStars} of {totalStars} stars
}
這邊再將傳進來的函數引數 setSelectedStars,傳入 onClick 的函數中,則所有的星星元件點擊之後,都會觸發 setSelectedStars( )。
const Star = ({ selected = true, onSelect = f => f }) => (
)
這邊也附上完整的 useState 程式碼:
import React from 'react'
import { useState } from 'react';
import { FaStar } from 'react-icons/fa'
const Star = ({ selected = true, onSelect = f => f }) => (
)
const createArray = length => [...Array(length)];
export function StarRating({ totalStars = 5 }) {
const [selectedStars, setSelectedStars] = useState(3)
return
{createArray(totalStars).map((n, i) =>
i}
onSelect={() => setSelectedStars(i + 1)} />
)}
{selectedStars} of {totalStars} stars
}
舊版的 React 狀態管理寫法
舊版是指比較早期的類別元件寫法,因為 hook 只能用於函式元件。這邊則是展示類別元件的狀態管理,不過因為類別元件本身有一些物件導向的概念,會比較難理解。
相較於 useState 去做資料狀態的預設以及更新,類別元件中使用的是建構子(constructor),建構子可以給予 starSelected 的預設值為 0,並且也另外針對類別中宣告的函式 change 進行綁定,最後再透過 render( ) 函式去做元件的渲染。
import React, { Component } from 'react'
import { FaStar } from 'react-icons/fa'
const Star = ({ selected = true }) => (
)
const createArray = length => [...Array(length)];
export default class StarRating extends Component {
constructor(props) {
super(props);
this.state = {
starSelected: 0
};
this.change = this.change.bind(this);
}
change(starSelected){
this.setState({starSelected});
}
render(){
const {totalStars} = this.props;
const {starSelected} = this.state;
return (
{[...Array(totalStars)].map((n,i)=>{
this.change(i+1)}
/>
})}
{starSelected} of {totalStars} stars
)
}
}
結語
這一篇React文章比較偏向寫程式,並且透過一個實際的例子來顯示視覺介面,也有另外針對早期的寫法,進行對比。如果有任何建議與疑問也歡迎留言!
如果喜歡此系列文章,請不吝於按下喜歡及分享,讓更多人看到唷~
引用
React白話文運動12-React Hook-useState 01
React白話文運動13-React Hook-useState 02
React 白話文運動系列
Babel & Webpack & NPM – React 白話文運動 07
JavaScript 高階函式 – React 白話文運動 04
JavaScript Async Await – React 白話文運動 03