Custom Hook là gì
Custom Hook là một công cụ cần thiết cho phép bạn thêm các chức năng đặc biệt, độc đáo vào các ứng dụng React của mình.
Khi bạn có 1 logic được sử dụng bởi nhiều component, bạn có thể trích xuất logic đó vào một Custom Hook.
Một số ví dụ có thể tạo 1 Custom Hook: useLocalStorage, useGetApi, useGetRedux...
Bạn có thể viết Custom Hook bao gồm một loạt các trường hợp sử dụng như xử lý form, annimation, counter và có thể nhiều hơn nữa mà chúng tôi chưa xem xét.
Hơn nữa, bạn có thể xây dựng các Hook dễ sử dụng như các tính năng tích hợp của React.
có hai quy tắc để tạo một hook:
- Custom Hook được đặt tên với tiền tố "use". (useLocalStorage hoặc useAuthentication)
- Custom Hook bao gồm built-in React Hooks hoặc các Custom Hook khác.
Nếu một Custom Hook không sử dụng bất kỳ hook nào bên trong, nó không phải là một Custom Hook và không nên có tiền tố "use".
cấu trúc cơ bản của 1 Custom Hook
import { useState, useEffect } from 'react';
import axios from 'axios';
axios.defaults.baseURL = 'https://jsonplaceholder.typicode.com';
const useFetch = (UrL: string) => { const [data, setData] = useState(null); const [error, setError] = useState(null); const [isLoading, setLoading] = useState(true); useEffect(() => { axios.get(UrL) .then((res) => setData(res.data)) .catch((err) => setError(err)) .finally(() => setLoading(false)); }, [UrL]); return { data, isLoading, error };
};
export default useFetch;
sử dụng Custom Hook trong Component khác:
const { data, isLoading, error } = useFetch('/posts');
if (isLoading) return <LoadingComponent />;
if (error) return <InvalidComponent />;
return (<> {/* html code */}
</>);
Note
Về cơ bản thì 1 Custom Hook có cấu trúc không khác mấy với 1 Component, sự khác biệt là Component chỉ có thể trả về 1 React.FC, trong khi Custom Hook muốn trả về gì cũng được.
Vì nó như 1 Component nên logic bên trong Custom Hook hoàn toàn có thể đưa vào trong 1 Component mà không có vấn đề gì. Nhưng nhắc lại, Custom Hook được dùng để đưa các logic sử dụng chung trong nhiều Component thành 1 logic, nếu chỉ sử dụng ở 1 nơi thôi thì việc tạo Custom Hook có vẻ không cần thiết. Cố gắng tránh việc trừu tượng hóa quá sớm.
Bây giờ các Functional Component có thể làm được nhiều việc hơn, code của bạn sẽ trở nên dài hơn. Điều này là bình thường - đừng cảm thấy như bạn phải ngay lập tức chia nó thành Hooks. Nhưng mình cũng khuyến khích bạn bắt đầu phát hiện các trường hợp mà Custom Hook có thể ẩn các logic phức tạp hoặc giúp gỡ rối một Component lộn xộn.
Câu hỏi
Code kiểu này có ảnh hưởng gì đến flow code không?
nó hoạt động theo cùng 1 cách, nếu quan sát kỹ, bạn sẽ nhận thấy không có bất kỳ thay đổi nào đối với logic.
Việc bắt đầu bằng "use" có cần thiết không?
Quy ước này rất quan trọng. Nếu không có nó, React sẽ không thể tự động kiểm tra Custom Hook của bạn có vi phạm quy tắc của Hooks hay không vì React không thể biết liệu một function nào đó có gọi đến Hook bên trong nó hay không.
2 Component sử dụng 1 Hook thì dữ liệu có bị chia sẻ không?
Không. Custom Hook là một cơ chế để sử dụng lại logic, mỗi khi bạn sử dụng Custom Hook, tất cả State và Effect bên trong đều bị cô lập hoàn toàn.
Làm thế nào để một Custom Hook có State bị cô lập?
Mỗi lần call đến một Hook sẽ có State riêng. Bởi vì trong code gọi Custom Hook trực tiếp, theo React, Component này chỉ gọi useState và useEffect. Và như ta đã học trước đó, ta có thể gọi useState, useEffect nhiều lần trong một Component, và chúng sẽ hoàn toàn độc lập.
Mẹo
Truyền thông tin giữa các Hook
Vì Hook là các hàm nên chúng ta có thể truyền thông tin giữa chúng.
const [recipientID, setRecipientID] = useState(1);
const isRecipientOnline = useFriendStatus(recipientID);
Bởi vì lệnh useState cung cấp cho chúng ta giá trị mới nhất của recipientID, chúng ta có thể chuyển nó vào useFriendStatusHook dưới dạng đối số.
Nếu chúng ta chọn một giá trị khác và cập nhật recipientID, useFriendStatusHook sẽ hủy kết quả khỏi recipientID trước đó và đăng ký mới recipientID được chọn.
useYourImagination()
Custom Hook cung cấp sự linh hoạt trong việc chia sẻ logic mà trước đây không thể có trong các React Component.
Ví dụ: có thể bạn có một Component phức tạp chứa nhiều State được quản lý theo cách đặc biệt. Lúc này useState không làm cho việc tập trung logic dễ dàng hơn, nhưng vẫn không muốn thêm thư viện Redux.
Bạn có thể viết nó như một Redux bản thu nhỏ:
Ví dụ này chưa được kiểm chứng, nên hãy xem nó như 1 ví dụ
Tạo Reducer phiên bản Fake:
function todosReducer(state, action) { switch (action.type) { case 'add': return [...state, { text: action.text, completed: false }]; // ... other actions ... default: return state; }
}
tạo 1 Store phiên bản Fake:
function useReducer(reducer, initialState) { const [state, setState] = useState(initialState); function dispatch(action) { const nextState = reducer(state, action); setState(nextState); } return [state, dispatch];
}
giờ thì có thể sử dụng nó trong code:
function Todos() { const [todos, dispatch] = useReducer(todosReducer, []); function handleAddClick(text) { dispatch({ type: 'add', text }); } // ...
}
Kết luận
- Custom Hook là 1 chức năng đặc biệt và độc đáo của React
- vì nó là 1 Hook nên khi sử dụng nó, props nhận được phải tạo biến, hoặc để trong useState, nói chung là sẽ không gọi được nó trong useEffect với Dynamic Params đâu
- Custom Hook thực chất chỉ di chuyển logic chung thành 1 Hook thôi, nhưng đừng lạm dụng nó quá, Functional Component dài hơn, làm nhiều việc hơn là chuyện bình thường