리액트 커스텀 훅
문제
-
React Component 는 View 렌더링의 역할이 중요하다
-
Component는 다음과 같은 로직을 중복적으로 담고 있을 수 있다.
-
데이터 필터링 또는 파싱작업
-
데이터 요청 / 응답 처리
-
인증 처리
-
-
이런 로직을 분리 한다면 View 그 차제 역할로 순수해지고, 간결해진다.
-
다만 저런 로직은 re-rendering과정에서 필요한 상태를 가지고 있을 수 있다.
-
React는 커스텀 훅을 통해서 View와 통합해서 렌더링 할 수 있는 방법을 제시한다.
데이터 통신이 필요한 코드
import React, { useState, useEffect } from "react";
const MyComponent = () => {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchData = async () => {
const url = "https://jsonplaceholder.typicode.com/todos";
const res = await fetch(url);
if (res.ok) {
const list = await res.json();
setData(list);
} else {
console.error("Network response was not ok");
}
setLoading(false);
};
fetchData();
}, []);
if (loading) {
return <p>Loading...</p>;
}
return (
<div>
<h1>Data from API</h1>
<ul>
{data.map((item) => (
<li key={item.id}>{item.title}</li>
))}
</ul>
</div>
);
};
view component 에서 통신로직 분리
useFetch 라는 커스텀훅을 만들어서 분리시킴
import React from 'react';
const MyComponent = () => {
const { data, loading } = useFetch({
url: "https://jsonplaceholder.typicode.com/posts",
});
if (loading) {
return <p>Loading...</p>;
}
return (
<div>
<h1>Data from API</h1>
<ul>
{data.map((item) => (
<li key={item.id}>{item.title}</li>
))}
</ul>
</div>
);
};
useFetch 커스텀 훅
단일책임원칙에 따라 구현
서비스 로직 불포함
특정 뷰 의존성없이 재사용 가능한 컴포넌트 개발
import React, { useState, useEffect } from "react";
const useFetch = ({ url }) => {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchData = async () => {
const res = await fetch(url);
const list = await res.json();
setData(list);
setLoading(false);
};
fetchData();
}, [url]);
return { data, loading };
};
Error handling
async 함수에서는 비동기 로직을 포함해서, try-catch-finally 처리가 가능하다.
(async function () {
try {
const res = await fetch(`http://localhost:3001/milestone2`);
} catch (e) {
console.error('exeception occured!!', e.message);
} finally {
...
}
}
useFetch 에 다양한 상태 반영
-
3가지를 결과로 반환
-
fetch 결과
-
error 메시지 결과
-
loading 상태
-
-
response 값이 false라면 response.staus 값을 error 메시지에 담아서 반환
-
그외 오류에 대해서 catch 로 잡아서, error 메시지를 반환.
useFetch 완성
import { useState, useEffect } from 'react';
const useFetch = ({ url }) => {
const [data, setData] = useState([]);
const [errorMsg, setErrorMsg] = useState(''); // 에러 메시지 상태 추가
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchData = async () => {
try {
const res = await fetch(url);
// HTTP 응답 상태 확인
if (!res.ok) {
setErrorMsg(`Response error. Status code: ${res.status}`);
return;
}
const list = await res.json();
setData(list);
} catch (e) {
console.error('Exception occurred!!', e.message);
setErrorMsg(e.message); // 예외 발생 시 에러 메시지 설정
} finally {
setLoading(false); // 요청 완료 후 로딩 상태 해제
}
};
fetchData();
}, [url]);
return { data, errorMsg, loading }; // 에러 메시지 반환
};
export default useFetch;