前情提要
在【理解 React useEffect 01】一文了解到 useEffect 的功能是:
useEffect 主要在呈現 (Render) 後觸發此 Hook 事件,並將取得的資料後再呈現到元件上。
也知道我們要怎麼在 useEffect 裡面拉 WebAPI 的資料;且已知 useEffect 再觸發的條件是:第二個參數【依賴 dependency】發生變化時,就會再觸發 useEffect 掛勾。
這一篇將會告訴各位,如何手動觸發 useEffect,達成程式碼重用的目標。
新需求:搜尋欲下載的主題
現在已經可以在元件載入時就下載【Redux】的資料,那如果現在要下載【React】時該怎麼做?使用 Input 元件可以輸入任意資料並下載其內容。
import React, { useState, useEffect } from "react"
import axios from "axios"
import "./styles.css"
export default function App() {
const [data, setData] = useState({ hits: [] })
const [query, setQuery] = useState("redux")
useEffect(() => {
async function fetchData() {
const result = await axios(
"https://hn.algolia.com/api/v1/search?query=redux"
)
setData(result.data)
}
console.log("hi")
fetchData()
}, [])
return (
<>
<input value={query} onChange={ event=>setQuery(event.target.value) } />
<ul>
{data.hits.map((item) => (
<li key={item.objectID}>
<a href={item.url}>{item.title}</a>
</li>
))}
</ul>
</>
)
}
給予參數的文字框和【query】狀態連動,就能再帶入 useEffect 掛勾裡:
import React, { useState, useEffect } from "react"
import axios from "axios"
import "./styles.css"
export default function App() {
const [data, setData] = useState({ hits: [] })
const [query, setQuery] = useState("redux")
useEffect(() => {
async function fetchData() {
const result = await axios(
`https://hn.algolia.com/api/v1/search?query=${query}`
)
setData(result.data)
}
console.log("hi")
fetchData()
}, [query])
return (
<>
<input value={query} onChange={ event=>setQuery(event.target.value) } />
<ul>
{data.hits.map((item) => (
<li key={item.objectID}>
<a href={item.url}>{item.title}</a>
</li>
))}
</ul>
</>
)
}
axios 裡的連結參數引用狀態【query】,而且依賴 query 變化來產生對應的副作用,故在第二個參數裡填入 query。現在我們只要每輸入一個字,都會立即向 WebAPI 拉資料。
改善無效的頻寬浪費
每打一個字就向 WebAPI 拉資料會常常進行無效查詢,若是以打完文字再查詢相對合乎實際應用的場合。所以再加入一個【搜尋】按鈕來決定何時才需要向 WebAPI 拉資料。
import React, { useState, useEffect } from "react"
import axios from "axios"
import "./styles.css"
export default function App() {
const [data, setData] = useState({ hits: [] })
const [query, setQuery] = useState("redux")
const [search, setSearch] = useState("redux")
useEffect(() => {
async function fetchData() {
const result = await axios(
`https://hn.algolia.com/api/v1/search?query=${search}`
)
setData(result.data)
}
console.log("hi")
fetchData()
}, [search])
return (
<>
<input value={query} onChange={ event=>setQuery(event.target.value) } />
<button onClick={ ()=>setSearch(query) }>Search</button>
<ul>
{data.hits.map((item) => (
<li key={item.objectID}>
<a href={item.url}>{item.title}</a>
</li>
))}
</ul>
</>
)
}
增加【search】狀態,並且把【query】限縮在文字框內;Search 按鈕按下後會將 query 傳到 search,以觸發 useEffect 掛勾,進而達成 useEffect 複用的目標。
重構:設計更直覺的設計
Search 作為參數查詢,使用 url 做大包狀態更直覺:
import React, { useState, useEffect } from "react"
import axios from "axios"
import "./styles.css"
const baseUrl = "https://hn.algolia.com/api/v1/search?query="
export default function App() {
const [data, setData] = useState({ hits: [] })
const [query, setQuery] = useState("redux")
const [url, setUrl] = useState(baseUrl+query)
useEffect(() => {
async function fetchData() {
const result = await axios(url)
setData(result.data)
}
console.log("hi")
fetchData()
}, [url])
return (
<>
<input value={query} onChange={ event=>setQuery(event.target.value) } />
<button onClick={ ()=>setUrl(baseUrl+query) }>Search</button>
<ul>
{data.hits.map((item) => (
<li key={item.objectID}>
<a href={item.url}>{item.title}</a>
</li>
))}
</ul>
</>
)
}
這裡說明【重構】,專案進行一段時間後,可以不定時進行程式碼重構,梳理『技術債』對自己負責。以此案例來說,把出現兩次以上的網址放到 baseUrl,減少打字的數量,並且把 search 狀態更名為 url。【React useEffect Step 3】
結論
useEffect 很多文章會直接導引到 useCallback 和 useMemo 等 Hook 結合,然而有時只是需要重用 useEffect 就能解決,【How to fetch data with React Hooks?】這篇文章前半著實是 useEffect 的入門好內容,有了對它的理解和變化,在學習其它的 Hook 就能少走許多冤枉路,筆者在這裡把精髓抽取出來並加上補充說明,原文後半是 useEffect 的補充變化,給有需要自刻框架的你。
學習 useEffect的資訊整理為這兩篇,分享給各位。
以上。
沒有留言:
張貼留言