iT邦幫忙

2021 iThome 鐵人賽

DAY 23
0
Modern Web

白話JavaScript系列 第 28

Day28-Custom Hook

前言

我們學習了效能優化、生命週期、React狀態等等,今天我們要來學習React的模組化,也就是custom hook。

  • use開頭,若不使用use開頭便無法辨識Hook的規則
  • React中允許內部使用其他Hooks
  • 把未來預期會重複使用的功能,包裝成函式,達成重複利用。

useFetch

今天我們來把fetch包裝成模組化。

前端會呼叫API的機會非常多,於是我們把fetch包裝成一個模組。

以下為目前的資料夾狀態,我們會在Hooks底下創建useFetch.js

https://ithelp.ithome.com.tw/upload/images/20210926/20130419AwuAyW1UaD.png

我們會先建立三個state,確認讀取狀態、資料、錯誤訊息

//useFetch.js
import {useEffect, useState} from 'react'

function useFetch(url) {
  const [isLoading, setIsLoading] = useState(false)
  const [data, setData] = useState('')
  const [error, setError] = useState('') 
  
  return {data, error, isLoading}
}
export default useFetch

基本狀態定型後,使用useEffect來作為讀取資料的副作用。

//useFetch.js
import {useEffect, useState} from 'react'

function useFetch(url) {
  const [isLoading, setIsLoading] = useState(false)
  const [data, setData] = useState('')
  const [error, setError] = useState('') 

  useEffect(() => {
    
  },[url]) 
  
  return {data, error, isLoading}
}

export default useFetch

接下來我們需要把邏輯放在useEffect中

我們所想的,當資料被塞入

  1. 把isLoading設為true,代表正在讀取
  2. 把url中的資料轉為json格式,並且塞入data state中
  3. 如果fetch狀態為reject,把錯誤報告塞入error state中
  4. 最後把isLoading的狀態設置為false
  5. 回傳三個數值
//useFetch.js
import {useEffect, useState} from 'react'

function useFetch(url) {
  const [isLoading, setIsLoading] = useState(false)
  const [data, setData] = useState('')
  const [error, setError] = useState('') 

  useEffect(() => {
    setIsLoading(true)
    fetch(url)
    .then((res) => res.json())
    .then((json) => setData(json))
    .catch((err) => setError(err))
    .finally(() => setIsLoading(false))
  },[url])
  
  return {data, error, isLoading}
}

export default useFetch

回到App.js,要來引入API

我們使用這個fake api來模擬API

使用解構賦值把data、isLoading、error抓取出來

  const {data, isLoading, error} = useFetch('https://jsonplaceholder.typicode.com/todos/1')
//App.js
import useFetch from '../Hooks/useFetch'

function App() {
  const {data, isLoading, error} = useFetch('https://jsonplaceholder.typicode.com/todos/1')
  
  if (isLoading) {
    return <h1>isLoading....</h1>
  } else if (error) {
    return <h1>data can't fetch</h1>
  } else {
    return (
      <div>
        <p>{data.userId}</p>
        <p>{data.id}</p>
        <p>{data.title}</p>
      </div>
    )
  }
}

export default App

這樣我們就可以很簡單完成每次獲取API的動作,也可以確保狀態、跟資料是符合的。

最後我們再把Loading分成一個組件,避免App.js中太多元素。

https://ithelp.ithome.com.tw/upload/images/20210926/20130419c9v1JpE5GP.png

//Loading.js
import React from 'react'

function Loading() {
  return (
    <div>
      <h1>Loading...</h1>
    </div>
  )
}

export default Loading

//App.js
import useFetch from '../Hooks/useFetch'
import Loading from './Loading'
function App() {
  const {data, isLoading, error} = useFetch('https://jsonplaceholder.typicode.com/todos/1')
  
  if (isLoading) {
    return <Loading />
  } else if (error) {
    return <h1>data can't fetch</h1>
  } else {
    return (
      <div>
        <p>{data.userId}</p>
        <p>{data.id}</p>
        <p>{data.title}</p>
      </div>
    )
  }
}

export default App

基本上我們就完成React的核心思想,切分組件、避免耦合性高、重複利用的技巧了!!!

/images/emoticon/emoticon01.gif


上一篇
Day27-useMemo
系列文
白話JavaScript28

尚未有邦友留言

立即登入留言