# 從 Hooks 開始,讓你的網頁 React 起來系列的閱讀筆記(21-22) ###### tags: `閱讀筆記` `前端筆記` `React` ## 完成章節: - 21-22(2021/11/28) ## `useMemo` 保存「值」 `useMemo()` 可以輸入兩個參數,第一個為函式,第二個為 dependency(Array),與 `useCallback()` 很像,但是`useMemo()` 會回傳第一個參數(也就是函式)執行的結果(值),如果 dependency 沒有改變的話就不會重新計算(換言之就是如果 dependency 沒有改變就連算都不算,直接回傳同樣的值!) 範例是用 `props` 接受父層的資料,如果父層的資料有改變,那麼就會觸發 `setSometing` re-render Components,屆時 WeatherIcon Component 必定會重新執行,就會得到父層新的資料,也因為 `useMemo` 是以原本的未改變的資料為 dependency,所以 `useMemo` 必然會重新運算得到新的值,等到 render 結束就會觸發 `useEffect` (因為其 dependency) 也改變了,所以就會執行 `useEffect` 的任務(觸發 `setSometing` re-render WeatherIcon component)。 ```javascript= // WeatherIcon.js // ... export function WeathcerIcon({ moment, currentWeatherCode }) { const [currentWeatherIcon, setCurrentWeatherIcon] = useState("isClear"); // 每次 render 都會執行 useMemo,但是只要 dependency 沒變就不會運算,直接給同樣的值 const theWeatherIcon = useMemo(() => weatherCode2Type(currentWeatherCode), [ currentWeatherCode ]); useEffect(() => { console.log("in useEffect from WeatherIcon"); const currentWeatherIcon = weatherCode2Type(currentWeatherCode); console.log(currentWeatherIcon); setCurrentWeatherIcon(currentWeatherIcon); // 用 useMemo 回傳的值來控制是否要觸發 setCurrentWeatherIcon 觸發 re-render }, [theWeatherIcon]); return ( <IconContainer>{weatherIcons[moment][currentWeatherIcon]}</IconContainer> ); } ``` *`useMemo` 是 rendering Component 時就會執行,只是會看 dependency 有沒有變才會運算第一個參數(也就是函式)* ### 用 `useMemo` 可以省略重複地複雜運算 1. first render component (WeatherApp) 2. 執行 render 3. first render component (WeatherIcon) 4. 執行 render 5. WeatherApp 的 first render component 結束(觸發 useEffect) 6. 收到資料了 7. WeatherIcon 的 first render component 結束(觸發 useEffect) 8. WeatherApp 收到 API 資料觸發 `setSometing` re-render Component 9. 執行 render 10. 執行 WeatherIcon 的 render 11. 因為 WeatherIcon 的 `useEffect` 的 dependency 有被更動,所以再次觸發 `setSometing` re-render Component 12. 繼續 re-render WeatherApp 剩下的 component  如果之後拉 API 沒改變 WeatherIcon `useMemo` 的 dependency(也就是地址),就不會觸發 WeatherIcon 的 `useEffect`,自然就只會因主要 Component WeatherApp 有因獲得 API 回應觸發 `setSometing` 執行的 re-render 順道 re-render WeatherIcon 一次而已。  **仔細發現就可以看到 LIFO(Last in, First out)的觀念,functional component 就是 function** 因為 WeatherApp 中的 `useEffect` 的任務是非同步的,所以會先執行 WeatherIcon render 後的 `useEffect` 後再回頭執行 WeatherApp `useEffect`。==要注意只要 Component first render 結束後就會觸發 `useEffect`。== 知道主要 Component 及小 Component 的 render + `useEffect` 執行順序之後再安排程式流程應該會有所幫助。 ```javascript= // WeatherApp. js // ... const fetchData = useCallback(() => { const fetchingData = async () => { // await 保證的是這段執行完畢(也就是兩個 Promise 都取得回應後 + .then 結束後)才會繼續往下執行 const [currentWeather, weatherForecast] = await Promise.all([ fetchCurrentWeather(), fetchWeatherForecast() ]); setWeatherElement({ ...currentWeather, ...weatherForecast }); }; fetchingData(); }, []); useEffect(() => { console.log("execute function in useEffect"); fetchData(); }, [fetchData]); // ... ``` ## 參考資料 1. [從 Hooks 開始,讓你的網頁 React 起來 21-22](https://ithelp.ithome.com.tw/users/20103315/ironman/2668) 2. [useMemo](https://zh-hant.reactjs.org/docs/hooks-reference.html#usememo)
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up