React
에서 가독성과 코드 재사용성을 향상 시키기 위해 도입된 개념Javascript
로 작성되며, 훅(Hook)이라는 이름에서 알 수 있듯이, 내부에서 React
의 기본 훅을 사용을 허용된다. useState
나 useEffect
같은 기본훅을 커스텀 훅 내부에서 사용가능react
에서의 커스텀 훅은 use
라는 접두사를 붙여서 사용해야한다.react
에서 제공하는 hook
허용, 나머지는 ❌useMount
처럼 애매한 목적의 커스텀훅을 만들어선 ❌커스텀훅 useOnlineState
function useOnlineStatus() {
const [isOnline, setIsOnline] = useState(true);
useEffect(() => {
function handleOnline() {
setIsOnline(true);
}
function handleOffline() {
setIsOnline(false);
}
globalThis.addEventListener('online', handleOnline);
globalThis.addEventListener('offline', handleOffline);
return () => {
globalThis.removeEventListener('online', handleOnline);
globalThis.removeEventListener('offline', handleOffline);
};
}, []);
return isOnline;
}
❓ 위 커스텀훅을 아래 코드에서 적용 시켰을때, 위 둘의 컴포넌트가 같은 상태를 공유할까
function StatusBar() {
const isOnline = useOnlineStatus();
// ...
}
function SaveButton() {
const isOnline = useOnlineStatus();
// ...
}
커스텀 훅으로 추출하기 이전으로 생각해보면?
function StatusBar() {
const [isOnline, setIsOnline] = useState(true);
useEffect(() => {
// ...
}, []);
// ...
}
function SaveButton() {
const [isOnline, setIsOnline] = useState(true);
useEffect(() => {
// ...
}, []);
// ...
}
기본적으로 fetch
와 관련된 커스텀훅이기때문에, useEffect()
를 사용한다.
매개변수로 endpoint, 즉 fetch
할 url을 동적으로 받으며, 세가지 상태를 가진다.
data
를 담는 [data, setData] = useState([]);
[isLoading, setIsLoading] = useState(false);
error
객체를 담는 역할을 하는 [error, setError] = useState(null);
try/catch
문으로 감싸며, 통신에 성공했을땐 setData
에 responseData
를 받아 data
상태를 update하며, error
가 발생했을땐, setError
에 error
객체를 담아 error
상태를 update한다.
📝 useFecthData.js
import { useEffect, useState } from 'react';
export default function useFetchData(endpoint) {
const [data, setData] = useState([]);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState(null);
useEffect(() => {
const controller = new AbortController();
setIsLoading(true);
async function fetchProducts() {
try {
const response = await fetch(endpoint, {
signal: controller.signal,
});
const responseData = await response.json();
setData(responseData);
} catch (error) {
if (!(error instanceof DOMException)) {
setError(error);
}
} finally {
setIsLoading(false);
}
}
fetchProducts();
// StrictMode(x2, detect impure function component)
// mount(1, 요청 1) → unmount (취소 1) → mount(2, 요청 1) -> 응답 1
return () => {
controller.abort();
};
}, [endpoint]);
return { data, isLoading, error };
}
또한 위 코드에서 AbortController
객체가사용되는데,
AbortController
의 abort
메서드로 useEffect
에서 cleanupFunction
내에서 fetch
를 취소하는 역할을 담당한다❓ 취소하는 이유는
React
에선 컴포넌트의 순수성을 판단하기위해 <StrictMode>
를 사용한다.
그러나 useEffect
는 최초 렌더링 시 1회가 무조건적으로 실행되는데 <StrictMode>
로 인하여, fetch
로 서버로부터 가져온 data
가 불필요하게 2번 호출 및 렌더링되어 웹의 성능 저하에 영향을 줄 수 있게 된다.
따라서, useEffect
에서 1번째 렌더링 후 컴포넌트가 unMount
될때, useEffect
의 cleanupFunction
에 의해 , 첫번째 fetch
요청을 취소하고 2번째 fetch
만 진행 할 수 있는 역할을 한다.
Abortcontroller를 활용한 커스텀 fetch 훅 감명 받았습니다. 좋아요 누르고 갈게요