[React] API연동 - useReducer 사용
useAsync.js
import { useReducer, useEffect } from 'react';
function reducer(state, action) {
switch (action.type) {
case 'LOADING':
return {
loading: true,
data: null,
error: null
};
case 'SUCCESS':
return {
loading: false,
data: action.data,
error: null
};
case 'ERROR':
return {
loading: false,
data: null,
error: action.error
};
default:
throw new Error(`Unhandled action type: ${action.type}`);
}
}
function useAsync(callback, deps = [], skip = false) {
console.log(skip)
const [state, dispatch] = useReducer(reducer, {
loading: false,
data: null,
error: false
});
const fetchData = async () => {
dispatch({ type: 'LOADING' });
try {
const data = await callback();
dispatch({ type: 'SUCCESS', data });
} catch (e) {
dispatch({ type: 'ERROR', error: e });
}
};
useEffect(() => {
console.log(skip)
if(skip) return;
fetchData();
// eslint 설정을 다음 줄에서만 비활성화
// eslint-disable-next-line
}, deps);
return [state, fetchData];
}
export default useAsync;
Users.js
import React, { useState, useEffect,useReducer } from 'react';
import axios from 'axios';
import useAsync from './useAsync';
async function getUsers(){
const response = await axios.get(
'https://jsonplaceholder.typicode.com/users'
);
return response.data
}
function Users() {
const [state, refetch] = useAsync(getUsers, [], true);
const {loading, data: users, error } = state;
if (loading) return <div>로딩중..</div>;
if (error) return <div>에러가 발생했습니다</div>;
if (!users) return <button onClick={refetch}>불러오기</button>;
return (
<>
<ul>
{users.map(user => (
<li key={user.id}>
{user.username} ({user.name})
</li>
))}
</ul>
<button onClick={refetch}>다시 불러오기</button>
</>
);
}
export default Users;
useAsync에서 3번째 파라미터로 skip을 추가했다. 기본값은 false이다.
Users에서 useAsync를 받아올 때, skip의 값을 true로 받았다. useAsync는 skip값이 true일 때 fetchData()함수를 실행하지 않으므로, Users컴포넌트에서는 if(!users) 에 걸려서 return <button onClick={refetch}>불러오기</button>; 을 리턴한다.
** skip값이 true면 refetch를 해도 계속 if(!users)에 걸려야 하지 않나? 왜 불러오기 버튼을 누르면 false인것처럼 동작을 하는지?
console.log(skip)을 찍어봐도 skip값은 계속 true인데..? useAsync()의 초기값을 true로 설정해도 동일한 결과가 나타난다.
👉 해결
useAsync.js에서 마지막에 return[state, fetchData] 가 있기때문에 skip여부와 상관없이 렌더링이 되는거였다..
useEffect는 초기 렌더링할 때 딱 한번 실행되서 불러오기 버튼만 나왔던 거였고, 이후부터는 skip여부에 상관없이 fetchData를 실행한다.
API 에 파라미터가 필요한 경우
useAsync에 skip = true 로 할 경우, useEffect에서 deps가 바뀔 때 마다 업데이트 되므로, id값의 변화에 따라 useEffect가 실행되어야 하는데 skip때문에 실행이 되지 않음. -> skip = true로 지정 시 id파라미터로 api를 불러올 수 없음
04. react-async 로 요청 상태 관리하기
로딩중 문제 해결하기
참고한 블로그
https://react.vlpt.us/integrate-api/03-useAsync.html