iT邦幫忙

2022 iThome 鐵人賽

DAY 27
0
Modern Web

跳脫MVC,Laravel + React 建立電商網站系列 第 27

Day 27 Reack Hook能吃嗎?

  • 分享至 

  • xImage
  •  

還記得在Day 8的時候,我有提到過一句話:State,只能在class Component之中使用。
但在前面的實作專案中,相信有眼尖的同學觀察到了:不管是範例還是我們自己建立的Component,
通通都是Function Component。
但為什麼還能使用State?而且State的寫法也有一些不一樣。

原因就是"Hook",在進入官網的hook章節就可以看到標題:
Hook 是 React 16.8 中增加的新功能。它讓你不必寫 class 就能使用 state 以及其他 React 的功能。

這裡直接比較兩種State的使用:

Class Component
這裡一樣拿Day8的官方範例

class Clock extends React.Component {  
  constructor(props) {  
    super(props);  
    this.state = {date: new Date()};  
  }  
  componentDidMount() { //class內的function不用寫function宣告,直接function name + 括號即可 
    this.timerID = setInterval(  
      () => this.tick(),  
      1000  
    );  
  }  
  componentWillUnmount() {  
    clearInterval(this.timerID);  
  }  
  tick() {  
    this.setState({  
      date: new Date()  
    });  
  }  
  render() {  
    return (  
      <div>  
        <h1>Hello, world!</h1>  
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>  
      </div>  
    );  
  }  
}  
const root = ReactDOM.createRoot(document.getElementById('root'));  
root.render(<Clock />);

這裡有幾個要注意的:
1.會把所有的數值都包成object然後寫到this.state之中
2.要多去繼承React.Component,還要多寫construct
3.其他地方要使用state要用 this.state.xxx
4.要寫一個render的方法在裡面return 資料

綜合上面的幾點,我認為使用class 的state使用上相對來說有點繁雜而且也沒那麼直觀。

相反的,我把上面的code改寫成 使用 Function Component
Function Component
ps.這裡除了借助State以外還有借助Effect的幫助

import React,{useState , useEffect } from "react"; 
import ReactDOM from 'react-dom'; 
function Clock(){ 
    const [clock , setClock] = useState(new Date()); 
     
    useEffect(() => { 
        let timerID = setInterval( () => { 
            setClock(new Date()) 
        } , 1000) 
        return () => clearInterval(timerID); 
         
    }); 
     
      return ( 
        <div> 
          <h1>Hello, world!</h1> 
          <h2>It is {clock.toLocaleTimeString()}.</h2> 
        </div> 
      ); 
     
  } 
   
  const clock = ReactDOM.createRoot(document.getElementById('clock')); 
  clock.render(<Clock />);

上面兩段code的輸出結果是一樣的,但明顯用下面的方式可讀性高很多,也簡短了很多步驟,整體在撰寫上也變得更簡單。
另外官方也有說明使用Hook的好處,所以我就不把文件的資料複製貼上~

主要我覺得這個東西會推出真正的原因是,現存很多js的專案都是使用function來做宣告,如果為了導入React要把所有function都改寫成class,會造成導入上的困擾

https://ithelp.ithome.com.tw/upload/images/20221001/201457039PectH4JDm.png

因為我還是React初學者,所以我今天只針對官方的兩個預設來做解析~
首先有一個通則:Hook並不會在class之中運作,而Hook出現的目的就是用來取代class

State Hook

State Hook的介紹

首先,在JavaScript的世界中,我們可以把function 宣告成一個變數,React是在這個基礎之上建立的,想當然也支持這種寫法

const Example = (props) => { 
  // 你可以在這裡使用 Hook! 
  return <div />; 
}
function Example(props) { 
  // 你可以在這裡使用 Hook! 
  return <div />; 
}

這兩段程式碼都是可以使用Hook的。

State Hook 的初始宣告

如果要在React Function Component 知終始用State Hook,起手式就是要在import react的地方宣告(把useState這個function引入到檔案中):

import React, { useState } from 'react';

這樣就可以在下面的code中使用State Hook了。

接下來,我們在過去使用Class Component的時候會在construct之中使用setState,並把需要使用的State包成一個object;然而在State Hook之中,我們把不同的State拆分出來,不包在一起,確實的把每個State切割。
因此會使用像這樣的語法:

const [state , setState] = useState(0);
const [clock , setClock] = useState(new Date());

透過多次的宣告來區分不同的State。

基本的宣告結構如下:

const [ {State名稱} , {變更State的方法} ] = useState( {State一開始的初始值} );

其他地方怎麼使用上面宣告的State?

因為在上面的state是直接用宣告的方式,實際上已經存在了變數;所以如果要使用state可以直接使用,不用像 Class Component 寫成 this.state.clock
State Hook 直接使用變數名稱clock即可

其他地方怎麼更新上面宣告的State?

在過去使用Class Component的時候,因為所有State都被打包成一個物件,所以如果要更新某一個State必須使用 更新物件的方式來針對特定數值更新this.setState({ clock: new Date()})
然而在State Hook之中,只需要呼叫最一開始設定的變更State的方法名稱,並將更新的數值當成參數丟入即可 setClock(new Date())


Effect Hook

Effect Hook的介紹

其實我覺得effect沒有像State一樣那麼的直觀好理解,根據官方文件:資料 fetch、設定 訂閱、或手動改變 React component 中的 DOM 都是 side effect 的範例。
當我們要使用到 關於生命週期 這個東西的時候,在Function Component必須使用Effect。

https://ithelp.ithome.com.tw/upload/images/20221001/20145703A0wAK6XeX3.png

我這裡把 我們在 Day22 做的商品詳細頁前端修改一下:
原本的code:

<div className="pt-2 max-w-6xl"> 
    <label>數量:</label> 
    <input type="number" value={amount} onChange={ amountChange }/> 
    <p id="price" className="text-red-600">總金額:{product.product_price * amount}</p> 
</div>

改成effect後:

useEffect( () => { 
    document.querySelector("#price").innerHTML = `總金額:${product.product_price * amount}`; 
} , [amount]);

<div className="pt-2 max-w-6xl"> 
    <label>數量:</label> 
    <input type="number" value={amount} onChange={ amountChange }/> 
    <p id="price" className="text-red-600"></p> 
</div>

在我認為,這裡改使用Effect Hook,是為了畫面邏輯的流程控制

Effect Hook的語法結構

Effect Hook的語法結構比State還要更簡單一些:useEffect(callback function, array) 這樣就好了。
callback function 必填,array選填。
在 Effect Hook 之中的array是選填,主要是用來判斷要不要執行這個effect;array會有以下三種狀況:
1.不填,useEffect會在每次畫面渲染時都會執行。
2.空陣列[] ,useEffect只會執行一次 (初次 render 之後)
3.array中有值,useEffect則會再該值發生改變後執行
參考來源
Effect Hook 會分成兩種:一種是需要清除的Effect,另一種則是不需要清除的Effect。

不需要清除的 Effect

官方情境舉例:
有時候,我們希望在 React 更新 DOM 之後執行一些額外的程式碼。網路請求、手動變更 DOM、和 logging,它們都是無需清除 effect 的常見範例。我們之所以這樣說,是因為我們可以執行它們,並立即忘記它們。讓我們比較一下 class 和 Hooks 如何讓我們表達這樣的 side effect。

在Class Component之中, 我們需要兩個生命週期方法來幫助我們達到目的:componentDidMount (第一次render)、componentDidUpdate (後續更新)。
如果使用Effect Hook,本身就可以利用array來控制,因此可以大幅度的簡化code。

https://ithelp.ithome.com.tw/upload/images/20221001/20145703kFL378qUXP.png

需要清除的 Effect

官方情境舉例:
例如,我們可能想要設定對某些外部資料來源的 subscription。在這種情況下,請務必進行清除,以免造成 memory leak!讓我們比較一下我們可以如何用 class 和 Hook 做到這一點。

在Class Component 之中,我們也需要借助生命週期方法來幫助我們清除資料:componentWillUnmount (清除)
如果使用Effect Hook,我們只需要在effect 之中回傳function,React 將在需要清除時執行它。(詳細可以操考上面的改寫clock)

https://ithelp.ithome.com.tw/upload/images/20221001/20145703ICqC17hJOw.png


Day 27 結語

其實Hook還有其他可供使用的Api,官方文件也把Effect的文件寫得 非(篇)常(幅)詳(很)細(長)
我個人認為Effect概念上比State抽象許多,使用起來也沒那麼直觀,所以我這裡只做簡單的理解;如果要做到Effect大師,還是需要到官方文件熟讀唷~

明天我們來試試看 React 常見的前端套件
那我們就明天見啦!


上一篇
Day 26 Laravel + React 實戰之路 -7電商轉換最後一哩路
下一篇
Day 28 React與常見的前端套件 - Swiper + SweetAlert
系列文
跳脫MVC,Laravel + React 建立電商網站30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言