iT邦幫忙

2022 iThome 鐵人賽

DAY 27
0
Modern Web

React Hook 不求人,建立自己的 Hook Libary系列 第 27

[DAY 27] 自己的Hook自己做!一些零碎的 hook 們

  • 分享至 

  • xImage
  •  

雖然能把一些複雜的邏輯通通整理起來很舒服,但有時候你只是想省一滴滴的麻煩,或是想圖一點乾淨或是清楚的程式碼,因此本篇要來看看這些可能只是弄弄命名、重新包裝,或許不一定需要,或許只是讓內心小宇宙開心一點的零碎 hook 們。

開始!

useInitEffect

第一次 render 後只執行一次 useEffect

function useInitEffect(cb) {
  useEffect(() => {
    cb()
  }, [])
}

useInitEffect(() => {
  console.log("ON INIT")
})

useUnmountEffect

當元件 un-mount 時才執行的 useEffect

function useUnmountEffect(cb) {
  useEffect(() => {
    return () => cb()
  }, [])
}

useUnmountEffect(() => {
  console.log("ON UN MOUNT")
})

useAfterInitEffect

跳過第一次 render 的執行,後續 render 才會執行

function useAfterInitEffect(cb, deps) {
  const initRef = useRef(true)
  useEffect(() => {
    if (initRef.current) {
      initRef.current = false
      return
    }

    return cb()
  }, deps)
}

useAfterInitEffect(() => {
  console.log("ON AFTER INIT")
})

useQuery

Next.js 中如果想要抓到 queryString,要先透過 useRouter 再進一步得到 object 之後,再獲取 query,如果覺得這樣太麻煩,那就...

function useQuery() {
 return useRouter().query 
}

const {id, status} = useQuery()

useNav

react-router 或是 Next.js 中如果想透過程式碼的方式(非元件,如: <Link/>)進行葉面轉換,要先 useNavigate / useRouter 然後進一步填入需要的東西,如果覺得太麻煩...

以 react-router 的 useNavigate() 舉例,預先整理好一組 key-value 的網址物件,然後透過傳入 key 再進一步使用:

function useNav(loaction) {
  const naviagte = useNavigate()
  
  return () => naviagte(URLs[location])
}

const goHome = useNav("home")
const goUserPage = useNav("user")

OR

function useNav() {
  const naviagte = useNavigate()
  
  return (location) => naviagte(URLs[location])
}

const nav = useNav()

nav("home")
nav("user")

useFormValue

如果你很明確知道要大量使用 input 時 (雖然你可能會選擇套件處理XD):

function useFormValue (init) {
  const [state, setState] = useState(init)

  const handleChange = name => evt => {
    setState(prev => ({...prev, [name]: evt.target.value }))
  }
  
  return [state, handleChange]
}

<input value={state.email} onChange={handleChange('email')} />

usePage

與前一個雷同,當你只是想換第幾頁時:

function usePage (init = 1) {
  const [state, setState] = useState(init)

  const handleChange = (page) => setState(page)
  const handlePrev = () => setState(p => p - 1)
  const handleNext = () => setState(p => p + 1)

  reutrn {page: state, handleChange, handlePrev, handleNext}  
}

useForm

當想使用 <form/>, onSubmit, 以及 formData 時會用到的內容:

function useForm() {
  const formId = useId()
  
  const onSubmit = (evt) => {
    evt.preventDefault()
    const formData = new FormData(evt.target)
    const data = {}
    for(const [k,v] of formData){
      data[k] = v
    }
    
    return data
  }
  
  return [formId, onSubmit]
}


const handleCreateMember = (evt) => {
  const data = onSubmit(evt)
  //操作 data 等等
}

<form id={formId}>
  <input />
</form>
<button type="submit" form={formId} />

useNotify

當你想幫一個非同步事件加上通知的包裝:

function useNotify(cb) {
  const [isPending, setIsPending] = useState(false)
  const [error, setError] = useState(null)
  
  const handler = async () => {
    setIsPending(true)
    //處理中通知可以塞這裡
    try {
      const res = await cb()
      //成功通知可以塞這裡
      return res
    } catch (error) {
      //失敗通知可以塞這裡
      setError(error)    
    } finally {
      setIsPending(false)
    }
  }
  
  return {handler, isPending, error}
}

不過很多 notification 套件都有提供 async/promise 的 method 可以使用,像是 react-toastify 的這一篇

useAPI

SWR 中有提到可以將 hook 變成可重複使用的方法,變化與設計的方式就因人而異:

function useMember(query) {
  return useSWR(member.url + query)
}

function useOrder(id) {
  return useSWR(order.url + id)
}

class MemberService {
  url
  
  useMemberList (...) {
    return useSWR(...)
  }
                  
  useOneMember(...) {
    return useSWR(...)    
  }                
}
    
class Service {
  url
  
  constructor (name) {
    url = url + api[name]
  
    this.useList = (...) => useSWR(...)
    this.useOne = (...) => useSWR(...)
    this.createOne = (...) => fetch(..., { method: 'POST' })
    //...
  }
  
}

結語

本篇沒什麼特別,雖然不一定用得到或包裝成獨立的 hook,但或許在特定的情境會非常好用,當然設計方式就會因應情境而有不同,看你想解決什麼問題再來下手看看。


上一篇
[DAY 26] 自己的Hook自己做! 用 IntersectionObserver 弄出動態的網站吧!
下一篇
[DAY 28] 自己的Hook自己測試!
系列文
React Hook 不求人,建立自己的 Hook Libary30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言