반응형
안녕하세요.
오늘은 한 개의 react custom hook으로 GET/POST/PUT/DELETE 등 여러 요청을 한 번에 관리해 보겠습니다.
hooks
useFetch.js
import { useState, useCallback } from 'react';
// 필요한 파라미터를 밖으로 리턴해준 메모이제이션 처리 된
// 중첩함수 sendRequest에서 받기 때문에
// 이 hook을 사용하는 component에서 useFetch함수에 useCallback과 같은
// 메모이제이션을 해줄 필요가 없음
const useFetch = () => {
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState(null);
const sendRequest = useCallback(async (requestConfig, applyData) => {
const { url, method, headers, body } = requestConfig;
setIsLoading(true);
setError(null);
try {
const response = await fetch(url, {
method: method ? method : 'GET',
headers: headers ? headers : {},
body: body ? JSON.stringify(body) : null,
});
if (!response.ok) {
throw new Error('Request failed!');
}
const data = await response.json();
applyData(data);
} catch (err) {
setError(err.message);
}
setIsLoading(false);
}, []);
return { isLoading, error, sendRequest };
};
export default useFetch;
보통 fetch를 하게되면 로딩, 실패 상태도 같이 관리해줘야 하기 때문에 useFetch hook에서 한 번에 관리합니다.
사용 예
app.js (GET)
import { useEffect, useState } from 'react';
import Lists from './components/Lists';
import NewList from './components/NewList';
import useFetch from './hooks/useFetch';
function App() {
const [lists, setLists] = useState([]);
const { isLoading, error, sendRequest: fetchLists } = useFetch();
useEffect(() => {
// 이 함수를 useEffect 밖으로 빼도 문제는 없지만, 무한루프에 빠지지 않으려면
// hooks의 상태변경으로 인해 컴포넌트가 재랜더링 될 때
// 함수도 재생성 되기 때문에 useCallback을 써줘야 함
const transformLists = (listObj) => {
const loadedLists = [];
for (const listKey in listObj) {
loadedLists.push({ id: listKey, text: listObj[listKey].text });
}
setLists(loadedLists);
};
fetchLists(
{url: 'https://@@@@@.firebaseio.com/lists.json'},
transformLists
);
}, []);
const listAddHandler = (list) => {
setLists((prevLists) => prevLists.concat(list));
};
return (
<>
<NewList onAddList={listAddHandler} />
<Lists items={lists} loading={isLoading} error={error} onFetch={fetchLists} />
</>
);
}
export default App;
app.js는 get 예시 입니다.
Lists는 그냥 데이터 받아서 뿌려주기만 하는 components라서 예시 코드 없습니다.
NewList.js (POST)
import ListAddForm from './ListAddForm';
import useFetch from '../../hooks/useFetch';
const NewList = (props) => {
const { isLoading, error, sendRequest: sendListRequest } = useFetch();
// 방법 1 (bind())
const createList = (listText, listData) => {
const generatedId = listData.name;
const createdList = { id: generatedId, text: listText };
props.onAddList(createdList);
};
// enterListHandler이 함수는 버튼 클릭 시에만 실행돼서
// sendListRequest()의 상태변경에의한 무한루프에 빠지지 않기 때문에
// useCallback을 사용하지 않아도 괜찮음
const enterListHandler = async (listText) => {
// 방법 2
// const createList = (listData) => {
// const generatedId = listData.name;
// const createdList = { id: generatedId, text: listText };
// props.onAddList(createdList);
// };
sendListRequest(
{
url: 'https://@@@@@.firebaseio.com/lists.json',
method: 'POST',
body: { text: listText },
headers: {
'Content-Type': 'application/json',
},
},
createList.bind(null, listText)
);
};
return (
<section>
<ListAddForm onEnterList={enterListHandler} loading={isLoading} />
{error && <p>{error}</p>}
</section>
);
};
export default NewLIst;
피드백, 질문, 댓글 언제나 환영입니다!
감사합니다 :)
반응형