iT邦幫忙

2022 iThome 鐵人賽

DAY 15
4
Software Development

React框架白話文運動系列 第 15

React白話文運動15-React Hook-useEffect 02

  • 分享至 

  • xImage
  •  

前言

嗨,我是Hogan
目前在經營自己的自媒體 hogan.tech
主要分享一些有關於程式碼、軟體和科技業經驗分享
有興趣的讀者可以進一步關注我,進而獲得更多資訊唷!

未來文章一併更新於此網站 Hogan.B Lab
並且包含多語系 繁體中文英文日文簡體中文
觀看分類:React 白話文運動其他系列

如果想要快速查找其他文章請點選目錄

成立 hogan.tech 的初衷是
希望每個正在這條路上探索的人,
都可以透過 Hogan.tech 嘗試進入程式領域。


前一篇介紹另一個 hook 函式

  1. useEffect 的概念
  2. useEffect 語法

這一篇則是會繼續深入介紹useEffect

  1. useEffect 生命週期
  2. useEffect dependency

複習

先來複習一下前一篇useEffect的實作

首先建立一個 checkBox 元件,先建立一個useState( ),除了給予初始值以外,也給了一個setting。

不過元件渲染後,還是希望針對已修改的狀態,更新元件以及資料,因此將

console.log(`checked: ${checked.toString()}`);

放入 useEffect( ) 函式之中,之後只要元件狀態有更新,就會重新渲染一次。

import React, { useState } from 'react'
import { useEffect } from 'react';

function CheckBox() {
    const [checked, setChecked] = useState(false);
    useEffect(() => {
        console.log(`checked: ${checked.toString()}`);
    })
    return (
        <>
            <input
                type="checkbox"
                value={checked}
                onChange={() => setChecked(checked => !checked)}
            />
            {checked ? "checked" : "not checked"}
        </>
    )
}

useEffect 生命週期

這邊可以先來看一下這個元件,如果直接執行這個元件,

function Component() {
    console.log("render components");
    useEffect(() => {
        console.log("useEffect trigger")
    })
    return (
        <>
            {console.log("render JSX")}
        </>
    )
}

如果呼叫上面的元件,會依照順序印出三行的結果

分別為

  1. render components
  2. render JSX
  3. useEffect trigger

理由是因為載入元件後會先執行裡面的函式

Component元件第二行會先被執行,印出 render components

接下來遇到 useEffect 則會擺到渲染後去執行

然後再回傳 JSX 時,執行裡面的程式,印出 render JSX

最後回傳完畢後再去執行useEffect裡面的函式,印出 useEffect trigger

這樣的執行順序也與元件的生命週期有關

以上面的流程來說

  1. 執行元件
  2. 渲染元件
  3. 執行useEffect 函式

那如果我們修改元件的狀態,元件因此重新渲染呢?

除了渲染元件的步驟以外,其實也會重新執行 useEffect 裡面的函式

import React from 'react'
import { useState } from 'react';
import { useEffect } from 'react';

export default function EffectComponent() {
    console.log("render components");
    const [value, setValue] = useState(0)
    useEffect(() => {
        console.log("useEffect trigger")
        console.log(value)
    }, [value])
    return (
        <>
            <button onClick={() => setValue(value + 1)}></button>
            {console.log("render JSX")}
        </>
    )
}

這邊另外搭配了 useState 給予元件一個狀態叫做value,點擊按鈕後可以讓 value 加一

如果實際執行程式,並且點擊按鈕後,會分別印出以下

  1. render components
  2. render JSX
  3. useEffect trigger
  4. 0
  5. render components
  6. render JSX
  7. useEffect trigger
  8. 1

不過這邊也要跟讀者強調一下,如果不熟悉 useEffect 的讀者,可能一不小心就會陷入無窮渲染

import React from 'react'
import { useState } from 'react';
import { useEffect } from 'react';

export default function EffectComponent() {
    console.log("render components");
    const [value, setValue] = useState(0)
    useEffect(() => {
        console.log(value)
        setData()
    })

    const setData = () => {
        setValue(value + 1)
    }
    return (
        <>
            <button onClick={setData}></button>
            {console.log("render JSX")}
        </>
    )
}

如果直接執行以上的程式,會看到 console 一直跑,並且數字一直往上,為什麼呢?

理由是因為,以上面的流程來說

  1. 執行元件
  2. 渲染元件
  3. 執行useEffect 內的 setData 函式
  4. setData 函式修改狀態
  5. 狀態被修改,執行useEffect 內的 setData 函式
  6. setData 函式修改狀態
  7. ....

就會進入無窮渲染


useEffect dependency

那麼我們要怎麼避免上面的情境呢?

在useEffect 的語法中

useEffect(callback function,[dependencies])

後面會放入一個陣列,陣列裡面擺入的就是dependency

也可以選擇一個空的陣列,或是直接不加入陣列,都會有不同的效果

image

這一張圖我覺得概念相當清晰,這邊也附上 原文網址

也相當推薦讀者可以看此文章,更熟悉 useEffect 的概念,回到dependency 本身

在useEffect 函式中,如果dependency 沒有任何改變,就不執行useEffect內的函式

如果放上空的陣列,則只會執行一次

import React from 'react'
import { useState } from 'react';
import { useEffect } from 'react';

export default function EffectComponent() {
    console.log("render components");
    const [value, setValue] = useState(0)
    useEffect(() => {
        setData()
    }, [])
    
    const setData = () => {
        console.log(value)
        setValue(value + 1)
    }
    return (
        <>
            <button onClick={setData}></button>
            {console.log("render JSX")}
        </>
    )
}

這邊也歡迎讀者自行試試看


結語

以我個人來說,我覺得useEffect 既好用又複雜,因為他需要去判斷裡面的相依性

但是好處是使用useEffect就可以解決很多事情

如果有任何建議與疑問也歡迎留言!

如果喜歡此系列文章,請不吝於按下喜歡及分享,讓更多人看到唷~


上一篇
React白話文運動14-React Hook-useEffect 01
下一篇
React白話文運動16-React Hook-useRef
系列文
React框架白話文運動30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言