
- ReactJS 教程
- ReactJS - 首頁
- ReactJS - 簡介
- ReactJS - 路線圖
- ReactJS - 安裝
- ReactJS - 特性
- ReactJS - 優點與缺點
- ReactJS - 架構
- ReactJS - 建立React應用
- ReactJS - JSX
- ReactJS - 元件
- ReactJS - 巢狀元件
- ReactJS - 使用新建立的元件
- ReactJS - 元件集合
- ReactJS - 樣式
- ReactJS - 屬性 (props)
- ReactJS - 使用屬性建立元件
- ReactJS - props 校驗
- ReactJS - 建構函式
- ReactJS - 元件生命週期
- ReactJS - 事件管理
- ReactJS - 建立一個事件感知元件
- ReactJS - 在Expense Manager APP中引入事件
- ReactJS - 狀態管理
- ReactJS - 狀態管理API
- ReactJS - 無狀態元件
- ReactJS - 使用React Hooks進行狀態管理
- ReactJS - 使用React Hooks進行元件生命週期管理
- ReactJS - 佈局元件
- ReactJS - 分頁
- ReactJS - Material UI
- ReactJS - Http客戶端程式設計
- ReactJS - 表單程式設計
- ReactJS - 受控元件
- ReactJS - 非受控元件
- ReactJS - Formik
- ReactJS - 條件渲染
- ReactJS - 列表
- ReactJS - Keys
- ReactJS - 路由
- ReactJS - Redux
- ReactJS - 動畫
- ReactJS - Bootstrap
- ReactJS - Map
- ReactJS - 表格
- ReactJS - 使用Flux管理狀態
- ReactJS - 測試
- ReactJS - CLI命令
- ReactJS - 構建和部署
- ReactJS - 示例
- Hooks
- ReactJS - Hooks簡介
- ReactJS - 使用useState
- ReactJS - 使用useEffect
- ReactJS - 使用useContext
- ReactJS - 使用useRef
- ReactJS - 使用useReducer
- ReactJS - 使用useCallback
- ReactJS - 使用useMemo
- ReactJS - 自定義Hooks
- ReactJS 高階
- ReactJS - 可訪問性
- ReactJS - 程式碼分割
- ReactJS - Context
- ReactJS - 錯誤邊界
- ReactJS - 轉發Refs
- ReactJS - Fragments
- ReactJS - 高階元件
- ReactJS - 與其他庫整合
- ReactJS - 效能最佳化
- ReactJS - Profiler API
- ReactJS - Portals
- ReactJS - 無ES6 ECMAScript的React
- ReactJS - 無JSX的React
- ReactJS - 調和
- ReactJS - Refs和DOM
- ReactJS - Render Props
- ReactJS - 靜態型別檢查
- ReactJS - Strict Mode
- ReactJS - Web Components
- 附加概念
- ReactJS - 日期選擇器
- ReactJS - Helmet
- ReactJS - 行內樣式
- ReactJS - PropTypes
- ReactJS - BrowserRouter
- ReactJS - DOM
- ReactJS - 走馬燈
- ReactJS - 圖示
- ReactJS - 表單元件
- ReactJS - 參考API
- ReactJS 有用資源
- ReactJS - 快速指南
- ReactJS - 有用資源
- ReactJS - 討論
ReactJS - 使用useEffect
React 提供了useEffect 用於在元件中執行副作用。一些副作用如下:
從外部來源獲取資料並更新渲染內容。
渲染後更新DOM元素。
訂閱
使用計時器
日誌記錄
在基於類的元件中,這些副作用是使用生命週期元件完成的。因此,useEffect hook 是以下生命週期事件的替代方案。
componentDidMount - 首次渲染完成後觸發。
componentDidUpdate - 由於屬性或狀態更改導致渲染更新後觸發。
componentWillUnmount - 元件銷燬期間解除安裝渲染內容後觸發。
讓我們在本節學習如何在元件中使用effect hook。
useEffect 的簽名
useEffect 的簽名如下:
useEffect( <update function>, <dependency> )
其中,更新函式的簽名如下:
{ // code return <clean up function> }
這裡:
更新函式 - 更新函式是在每個渲染階段後執行的函式。這對應於componentDidMount 和componentDidUpdate 事件。
依賴項 - 依賴項是一個數組,其中包含函式所依賴的所有變數。指定依賴項對於最佳化 effect hook 至關重要。通常,更新函式在每次渲染後都會被呼叫。有時不需要在每次渲染時都執行更新函式。讓我們考慮一下,我們正在從外部來源獲取資料並在渲染階段之後更新它,如下所示:
const [data, setDate] = useState({}) const [toggle, setToggle] = useState(false) const [id, setID] = useState(0) useEffect( () => { fetch('/data/url/', {id: id}).then( fetchedData => setData(fetchedData) ) }) // code
每當data 和toggle 變數更新時,元件都會重新渲染。但是,正如您所看到的,我們不需要在每次更新toggle狀態時都執行定義的effect。為了解決這個問題,我們可以傳遞一個空依賴項,如下所示:
const [data, setDate] = useState({}) const [toggle, setToggle] = useState(false) const [id, setID] = useState(0) useEffect( () => { fetch('/data/url/', { id: id }).then( fetchedData => setData(fetchedData) ) }, [])
上面的程式碼只會在第一次渲染後執行一次 effect。儘管它會修復問題,但 effect 必須在每次id更改時執行。為了實現這一點,我們可以將id作為 effect 的依賴項包含在內,如下所示:
const [data, setDate] = useState({}) const [toggle, setToggle] = useState(false) const [id, setID] = useState(0) useEffect( () => { fetch('/data/url/', { id: id }).then( fetchedData => setData(fetchedData) ) }, [id])
這將確保 effect 只會在id修改後重新執行。
清理函式 - 清理函式用於在使用訂閱函式和計時器函式時進行清理工作,如下所示:
const [time, setTime] = useState(new Date()) useEffect(() => { let interval = setInterval(() => { setTime(new Date()) }, 1000) return () => clearInterval(interval) }, [time])
讓我們在後面的章節中建立一個完整的應用程式來理解清理函式。
effect hook 的特性
effect hook 的一些顯著特性如下:
React 允許在函式元件中使用多個 effect hook。這將幫助我們為每個副作用編寫一個函式,並將其設定為單獨的 effect。
每個 hook 將按照宣告的順序執行。開發者應確保 effect 的宣告順序正確。
依賴項特性可用於提高副作用的效能和正確性。
清理函式可以防止記憶體洩漏和不必要的事件觸發。
使用 effect 獲取資料
在本節中,讓我們建立一個應用程式,該應用程式將從外部來源獲取資料並使用useEffect hook 渲染它。
首先,建立一個新的React應用程式,並使用以下命令啟動它。
create-react-app myapp cd myapp npm start
接下來,在元件資料夾下建立一個React元件NameList(src/components/NameList.js)
function NameList() { return <div>names</div> } export default NameList
這裡,NameList元件的目的是展示流行的常見名字列表。
接下來,更新根元件App.js以使用新建立的NameList元件。
import NameList from "./components/NameList"; function App() { return ( <div style={{ padding: "5px"}}> <NameList /> </div> ); } export default App;
接下來,建立一個json檔案names.json(public/json/names.json),並以json格式儲存流行的名稱,如下所示。
[ { "id": 1, "name": "Liam" }, { "id": 2, "name": "Olivia" }, { "id": 3, "name": "Noah" }, { "id": 4, "name": "Emma" }, { "id": 5, "name": "Oliver" }, { "id": 6, "name": "Charlotte" }, { "id": 7, "name": "Elijah" }, { "id": 8, "name": "Amelia" }, { "id": 9, "name": "James" }, { "id": 10, "name": "Ava" }, { "id": 11, "name": "William" }, { "id": 12, "name": "Sophia" }, { "id": 13, "name": "Benjamin" }, { "id": 14, "name": "Isabella" }, { "id": 15, "name": "Lucas" }, { "id": 16, "name": "Mia" }, { "id": 17, "name": "Henry" }, { "id": 18, "name": "Evelyn" }, { "id": 19, "name": "Theodore" }, { "id": 20, "name": "Harper" } ]
接下來,建立一個新的狀態變數data,用於在NameList元件中儲存流行的名稱,如下所示:
const [data, setData] = useState([])
接下來,建立一個新的狀態變數isLoading來儲存載入狀態,如下所示:
const [isLoading, setLoading] = useState([])
接下來,使用fetch方法從json檔案獲取流行的名稱,並將其設定到useEffect hook內的data狀態變數中。
useEffect(() => { setTimeout(() => { fetch("json/names.json") .then( (response) => response.json()) .then( (json) => { console.log(json); setLoading(false); setData(json); } ) }, 2000) })
這裡我們有:
使用setTimout方法來模擬載入過程。
使用fetch方法獲取json檔案。
使用json方法解析json檔案。
使用setData將從json檔案中解析的名稱設定為data狀態變數。
使用setLoading設定載入狀態。
接下來,使用map方法渲染名稱。在獲取過程中,顯示載入狀態。
<div> {isLoading && <span>loading...</span>} {!isLoading && data && <span>Popular names: </span>} {!isLoading && data && data.map((item) => <span key={item.id}>{item.name} </span> )} </div>
這裡我們有:
使用isLoading顯示載入狀態。
使用data變數顯示流行名稱列表。
NameList元件的完整原始碼如下:
import { useState, useEffect } from "react" function NameList() { const [data, setData] = useState([]) const [isLoading, setLoading] = useState([]) useEffect(() => { setTimeout(() => { fetch("json/names.json") .then( (response) => response.json()) .then( (json) => { console.log(json); setLoading(false); setData(json); } ) }, 2000) }) return ( <div> {isLoading && <span>loading...</span>} {!isLoading && data && <span>Popular names: </span>} {!isLoading && data && data.map((item) => <span key={item.id}>{item.name} </span> )} </div> ) } export default NameList
接下來,開啟瀏覽器並檢查應用程式。它將顯示載入狀態,2秒後,它將獲取json並顯示流行的名稱,如下所示:


DOM操作
useEffect hook 可用於使用DOM及其方法操作文件。它確保其中的程式碼只在DOM準備就緒後執行。讓我們更改我們的名稱列表應用程式並使用DOM操作更新頁面的標題。
首先,開啟NameList元件,並根據載入狀態新增文件標題,如下所示:
useEffect(() => { if(isLoading) document.title = "Loading popular names..." else document.title = "Popular name list" setTimeout(() => { fetch("json/names.json") .then( (response) => response.json()) .then( (json) => { console.log(json); setLoading(false); setData(json);} ) }, 2000) })
在這裡,我們使用了DOM物件document.title來更新頁面的標題。
最後,開啟瀏覽器並檢查文件標題如何透過DOM操作更新。


清理函式
useEffect 可用於在元件從頁面文件解除安裝期間刪除清理函式,例如clearInterval、removeEventListener等。這將防止記憶體洩漏並提高效能。為此,我們可以建立我們自己的清理函式並將其從useEffect回撥引數返回。
讓我們更改我們的名稱列表應用程式以使用setInterval代替setTimeout,然後使用clearInterval在解除安裝元件期間刪除設定的回撥函式。
首先,開啟NameList元件並更新useEffect部分,如下所示:
useEffect(() => { if(isLoading) document.title = "Loading popular names..." else document.title = "Popular name list" let interval = setInterval(() => { setLoading(true) fetch("json/names.json") .then( (response) => response.json()) .then( (json) => { console.log(json); setLoading(false); setData(json);} ) }, 5000) return () => { clearInterval(interval) } })
這裡我們有:
使用setImterval每5秒更新一次流行名稱。
在清理函式中使用clearInterval在解除安裝元件期間刪除setInterval。
最後,開啟瀏覽器並檢查應用程式的行為。我們將看到資料每5秒更新一次。當元件解除安裝時,clearInterval將在後臺呼叫。
總結
useEffect是函式元件的重要特性,使元件能夠使用生命週期事件。它幫助函式元件提供具有可預測性和最佳化效能的豐富功能。