2024-01-08
【React新手村】useEffect要幹嘛?

原文發表於 Medium。

有個故事是這樣的,有一位名叫尤莉的工程師,她最近被推派負責公司的前端專案。這個專案是一個複雜的前端應用程式,採用了React 框架。
尤莉是一位有經驗的工程師,但而她之前並沒有太多的React經驗。在她開發功能時,遇到了些資料呈現上的問題。例如有一次,尤莉建立了一個儲存和顯示用戶個人檔案的功能,該功能包括名字、電子郵件地址和頭像。然而,她在渲染用戶個人檔案頁面時,發現有時候用戶的頭像顯示並不正確。
A.容易失敗的作法
import React, { useState } from 'react';
const UserProfilePage = ({ userId }) => {
const [userData, setUserData] = useState({});
const [avatarUrl, setAvatarUrl] = useState('');
// 用戶資料的非同步加載
const loadUserData = async () => {
const response = await fetch(`api/users/${userId}`);
const data = await response.json();
setUserData(data);
setAvatarUrl(data.avatarUrl); // 這裡有潛在的問題,可能 avatarUrl 還沒有正確地加載完成
};
// 初次渲染時加載用戶資料
loadUserData();
return (
<div>
<h2>{userData.name}</h2>
<img src={avatarUrl} alt="User Avatar" />
</div>
);
};
export default UserProfilePage;
尤莉深入調查,發現問題出現的原因是由於資料傳遞的時差:用戶資料的加載是不同步的,而在渲染階段,頭像的 URL 還沒有正確地加載完成。因此就導致在渲染時,頭像 URL 是空的或不完整的。這是一個亟待解決的糟糕問題,因為在用戶檔案頁面上,頭像的顯示對用戶體驗至關重要。
尤莉嘗試過一些解決方法,例如強制重新渲染、使用非同步函式等,但都沒有完全解決問題。
最終,她使用 useEffect 來處理用戶資料的不同步加載過程,一旦資料加載完成,就更新 React 狀態,觸發頁面重新渲染。這確保了在用戶資料完全加載之前,頭像不會被渲染到頁面上,做法如下:
B.正規的React作法
import React, { useState, useEffect } from 'react';
const UserProfilePage = ({ userId }) => {
const [userData, setUserData] = useState({});
const [avatarUrl, setAvatarUrl] = useState('');
// 用戶資料的非同步加載
const loadUserData = async () => {
const response = await fetch(`api/users/${userId}`);
const data = await response.json();
setUserData(data);
setAvatarUrl(data.avatarUrl);
};
// 使用 useEffect確保在初次渲染時確實加載了用戶資料
useEffect(() => {
loadUserData();
}, []); // 第二個參數是空Array,沒有其他的依賴條件,所以這個效果只會在初次渲染時執行
return (
<div>
<h2>{userData.name}</h2>
<img src={avatarUrl} alt="User Avatar" />
</div>
);
};
export default UserProfilePage;
這樣解決了用戶頭像顯示不正確的問題,並且尤莉對 useEffect 的運用有了更深的理解,也讓她更加熟練地應對日後的專案。
各位夥伴,由於資料是許多網頁的活水,只要資料停止更新,網頁幾乎可以說是『死了』,但要如何更新資料呢?
在過去沒有前端框架的時代會使用類似上面艾莉一開始使用的A方法,使用async/await或.then鏈直接使用非同步方式處理資料。但在React上,每一次的畫面渲染都有固定的「生命週期」,在開始渲染的時候,若遠方傳來的資料尚未準備好,那這一切就都破空而起,造成一堆的不正常顯示。
因此我們需要透過useEffect來確保資料上車之後,再開動我們的渲染列車。
useEffect是 React 中一個用於處理副作用操作的 Hook。副作用指的是那些不直接參與 React 渲染的操作,例如資料的加載、掛載用戶事件、手動修改 DOM 等。useEffect提供了一種在 React 函數組件中處理這些副作用的方式。
useEffect 是 React 中一個用於處理副作用操作的 Hook。副作用指的是那些不直接參與 React 渲染的操作,例如資料的加載、掛載用戶事件、手動修改 DOM 等。useEffect 提供了一種在 React 函數組件中處理這些副作用的方式。
何時要使用 useEffect
大概有以下三個場景:
- 資料加載: 當需要從伺服器或其他資源中加載資料時,可以使用
useEffect來發起非同步操作。 - 掛載用戶事件: 如果需要掛載用戶的輸入事件(如滾動、鍵盤輸入等),可以在
useEffect中進行設定。 - 操作 DOM: 對於需要直接操作 DOM 的情況,也可以使用
useEffect。
大部分使用的時機集中在第一點與第二點。
useEffect 的基本形式
useEffect(() => {
// 執行副作用操作的程式碼
return () => {
// 清除副作用操作的程式碼(非必要)
};
}, []);//dependencies-依賴條件的Array,空白代表只在第一次渲染時執行一次。
- 第一個參數是一個函式,我們在其中處理各種副作用,如加載資料等等。
- 第二個參數是一個Array,包含影響副作用的變數,當這些變數發生變化時,
useEffect會重新執行。如果省略第二個參數,則useEffect在每次渲染後都會執行。
- 第二個參數是一個Array,包含影響副作用的變數,當這些變數發生變化時,
useEffect 的原理:
- 第一次渲染: 當 React 首次渲染組件時,
useEffect中的副作用程式碼會被執行。 - 後續渲染: 如果提供了第二個參數(dependencies),則 React 會比較當前渲染和前一次渲染的 dependencies 是否有變化,如果有變化,則執行
useEffect中的副作用程式碼。 - 組件卸載: 如果組件即將卸載或
useEffect的 dependencies 發生變化,React 會執行清除函數(此處最常用到的場景就是setTimeout這樣的計時器清除,實際用到的機會不多)。
簡單來說,useEffect 提供了一個在 React 函數組件中處理副作用的機制,並確保這些副作用的執行是可控的。
祝大家天天有coding,天天有成長。我是一個半路出家卻把coding當作興趣,且不斷鑽研技巧的開發者,希望有朝一日能成為全然獨當一面的技術大神。