React 를 이용하여 개발하는 경우에 다른 컴포넌트이지만 같은 로직을 이용하는 것을 많이 경험해보았을 것이다. React 는 함수형 컴포넌트를 통해 반복되는 훅 활용 메서드를 하나로 통일하고 줄임으로써 더 간결하고 명료하게 상태관리 로직을 재활용할 수 있다.
사용하기 앞서 Custom Hook 에는 naming 규칙이 있다.
use
를 사용한다.지난 솔로프로젝트에서는 API 를 이용하여 products 를 불러오는 API 를 매 페이지마다 코드를 작성해야 했다.
useEffect(() => {
const fetchData = async () => {
try {
const res = await axios.get(
"http://cozshopping.codestates-seb.link/api/v1/products?count=4"
);
setItems(res.data);
} catch (error) {
setError("데이터를 가져오는 도중에 에러가 발생했습니다.");
console.log(error);
}
};
fetchData();
}, []);
이런 코드를 Custom Hook 을 이용해 하나의 파일로 통일하여 사용할 수 있다.
//useFetch.js
import { useState, useEffect } from "react";
import axios from "axios";
export const useFetch = (url) => {
const [data, setData] = useState([]);
const [error, setError] = useState(false);
useEffect(() => {
const fetchData = async () => {
try {
const res = await axios.get(url)
setData(res.data);
} catch (error) {
setError("데이터를 가져오는 도중에 에러가 발생했습니다.");
console.log(error);
}
};
fetchData();
}, []);
return [data, error];
}
//useFetch 를 사용할 컴포넌트
import useFetch from "useFetch";
function App() {
//~생략
const url = `...`;
const [data, error] = useFetch(url);
//...
}
다시 정리하자면, 동일한 로직을 불필요하게 여러 컴포넌트에서 여러 번 쓰는 것은 메모리를 불필요하게 낭비시키는 것뿐만 아니라 코드를 더 길게 지게함으로써 보기 좋지 못한 코드가 될 수 있다.
Custom Hook 을 이용하여
React 는 SPA(Single Page Application)으로 첫 렌더링을 할 때, 필요하지 않는 컴포넌트까지 한 번에 불러오기 때문에 시간이 꽤 걸린다. 꼭 코드 파일의 최상단에서 import
한 컴포넌트를 정적 static 으로 불러오는 방법을 사용했다. 하지만, 동적 dynamic 으로 불러와 필요할 때만 불러와 공간과 시간을 효율적으로 사용할 수 있는 방법인 React.lazy
와 Suspense
가 있다.
두 가지 React 메서드는 꼭 함께 사용되어야 하고, 동적으로 불러옴으로써 첫 렌더링 지연시간을 줄이는 역할을 한다.
React.lazy()
는 사용할 컴포넌트를 동적으로 import
한다는 의미로 사용된다.
Suspense
는 Router 를 이용해 해당 path 들로 컴포넌트가 나뉘어지기 전 로딩하는 시간에 자동적으로 아직 컴포넌트가 렌더링이 준비되지 않으면 로딩화면을 나타내고, 로딩이 완료되면 컴포넌트를 보여주는 기능을 한다. 이는 굳이 사용자가 로딩 컴포넌트를 작성할 필요가 없어 편리하다.
//App.js -> 페이지를 분기하는 작업에서 적용시키는 것이 좋다
import { Suspense, lazy } from "react";
import { BrowserRouter , Routes, Route } from "react-router-dom";
//React.lazy로 import를 감싼다.
const Home = lazy(() => import('./Home'));
const About = lazy(() => import('./About'));
const Loading = lazy(() => import('/Loading'));
const App = () => {
return(
<BrowserRouter>
<Suspense fallback={<Loading/>}>
//fallback 속성에서 Loading 화면으로 사용할 컴포넌트를 설정해준다.
<Routes>
<Route path="/" element={<Home/>}/>
<Route path="/about" element={<About/>}/>
</Routes>
</Suspense>
</BrowserRouter>
)
}