- 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是函式元件的重要特性,使元件能夠使用生命週期事件。它幫助函式元件提供具有可預測性和最佳化效能的豐富功能。