Khi làm việc với ReactJS chắc hẳn bạn không còn xa lạ với các hooks như useState, useRef, useEffect,.... Ngoài các hooks có sẵn, bạn có thể tự tạo ra các hooks mới tùy theo chức năng của nó (custom hooks). Trong bài viết này, mình sẽ hướng dẫn các bạn tạo 2 hooks là useWindowSize và useDebounce.
1. Custom hooks là gì ?
Custom hooks là việc các bạn tự tạo ra một hook mới với chức năng riêng biệt của nó. Việc này giúp tách phần code logic ra khỏi UI giúp code tường minh, dễ quản lý hơn, tránh lặp lại code và tái sử dụng.
Ví dụ khi bạn không dùng custom hook:
import { useState, useEffect } from 'react'
import Sidebar from 'components/Sidebar'
const App = () => {
const [width, setWidth] = useState<number>(window.innerWidth)
useEffect(() => {
const handler = () => {
setWidth(window.innerWidth)
}
window.addEventListener('resize', handler)
return () => {
window.removeEventListener('resize', handler)
}
}, [])
return (
<>
{width >= 1024 && <Sidebar />}
</>
)
}
và bây giờ nếu bạn muốn dùng window width ở component khác thì phải lặp lại phần code trên. Đây là lúc custom hooks phát huy tác dụng.
2. Xây dựng custom hooks
Cùng tạo tạo ra hook useWindowSize để giải quyết vấn đề trên nào.
import { useState, useEffect } from 'react'
export const useWindowSize = () => {
const [windowSize, setWindowSize] = useState({
width: window.innerWidth,
height: window.innerHeight,
})
useEffect(() => {
const handler = () => {
setWindowSize({
width: window.innerWidth,
height: window.innerHeight,
})
}
window.addEventListener('resize', handler)
return () => {
window.removeEventListener('resize', handler)
}
}, [])
return windowSize
}
Và đây là thành quả của chúng ta, bạn có thể sử dụng hook useWindowSize ở bất kì component nào.
import { useWindowSize } from 'hooks'
const App = () => {
const { width, height } = useWindowSize()
return (
<>
{width >= 1024 && <Sidebar />}
</>
)
}
Hook tiếp theo mình muốn giới thiệu các bạn đó useDebounce. Ví dụ khi bạn gõ tìm kiếm ở ô input thì sẽ hiển thị những gợi ý từ dữ liệu bạn nhập vào.
Ở đây khi bạn dùng onChange cho input, bạn sẽ không muốn phải call api liên tục, người dùng gõ 50 từ sẽ call api 50 lần. Ý tưởng là bạn sẽ setTimeout một khoản thời gian ngắn sau khi dười dùng dừng gõ mới call api. Cùng mình thực hiện nào.
import { useState, useEffect } from 'react'
export const useDebounce = <T>(
value: T,
delay: number,
cb: (value?: T) => Promise<void>,
) => {
const [debouncedValue, setDebouncedValue] = useState<T>(value)
useEffect(() => {
const handler = setTimeout(async () => {
setDebouncedValue(value)
await cb(value)
}, delay)
return () => {
clearTimeout(handler)
}
}, [value, delay])
return debouncedValue
}
- Value: là giá trị ô input.
- delay: là thời gian delay việc thực hiện hàm callback(miliseconds).
- cb: là callback ta muốn thực hiện sau khoảng thời gian delay trên.
Vậy là xong, khi cần dùng ta chỉ cần import
vào dùng thôi.
import { useDebounce, useState } from 'hooks'
import axios from 'axios'
const App = () => {
const [suggestionList, setSuggestionList] = useState([])
const [q, setQ] = useState('')
useDebounce(q, 400, async value => {
const response = await axios.get(...)
setSuggestionList(response.data)
})
return (
<div>
<input onChange={setQ.bind(this, e.target.value)} type='text' />
{suggestionList.map(...)}
</div>
)
}
Tạm kết
Trên đây là những kiến thức mình muốn chia sẻ đến các bạn về custom hooks trong ReactJS. Đến đây chắc hẳn các bạn đã thấy được sự lợi hại của nó. Đây là những kiến thức cơ bản nhưng hết sức quan trọng. Mong bài viết có thể giúp ích cho bạn.