React
[React] useReducer 복습
Puft
2024. 1. 30. 18:34
useReducer는 개발을 하면서 많이 사용할 것 같아서
복습하는 시간을 가져보도록 하겠습니다.
import React, { useState, useEffect } from 'react';
import axios from 'axios';
function Users() {
const [users, setUsers] = useState(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
useEffect(() => {
const fetchUsers = async () => {
try {
// 요청이 시작 할 때에는 error 와 users 를 초기화하고
setError(null);
setUsers(null);
// loading 상태를 true 로 바꿉니다.
setLoading(true);
const response = await axios.get(
);
setUsers(response.data); // 데이터는 response.data 안에 들어있습니다.
} catch (e) {
setError(e);
}
setLoading(false);
};
fetchUsers();
}, []);
if (loading) return <div>로딩중..</div>;
if (error) return <div>에러가 발생했습니다</div>;
if (!users) return null;
return (
<ul>
{users.map(user => (
<li key={user.id}>
{user.username} ({user.name})
</li>
))}
</ul>
);
}
export default Users;
이전 시간에 사용했던 코드입니다.
이 코드는 useReducer를 사용해서 setState와 같은 변경 구문을 없앨수도 있습니다.
import React, { useEffect, useReducer } from 'react';
import axios from 'axios';
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 Users() {
const [state, dispatch] = useReducer(reducer, {
loading: false,
data: null,
error: null
});
const fetchUsers = async () => {
dispatch({ type: 'LOADING' });
try {
const response = await axios.get(
);
dispatch({ type: 'SUCCESS', data: response.data });
} catch (e) {
dispatch({ type: 'ERROR', error: e });
}
};
useEffect(() => {
fetchUsers();
}, []);
const { loading, data: users, error } = state; // state.data 를 users 키워드로 조회
if (loading) return <div>로딩중..</div>;
if (error) return <div>에러가 발생했습니다</div>;
if (!users) return null;
return (
<>
<ul>
{users.map(user => (
<li key={user.id}>
{user.username} ({user.name})
</li>
))}
</ul>
<button onClick={fetchUsers}>다시 불러오기</button>
</>
);
}
export default Users;
이렇게 스위치 문으로 각 상태에 따라서
로직을 분리해서 다른 곳에서 쉽게 비동기처리를 할 수 있습니다.
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 Users() {
const [state, dispatch] = useReducer(reducer, {
loading: false,
data: null,
error: null
});
useReducer를 선언할 때는 dispatch라는 파라미터가 존재하는데
이 곳에는 어떤 state를 어떻게 바꿀 것인지에 대한 정보가 들어갑니다.
const fetchUsers = async () => {
dispatch({ type: 'LOADING' });
try {
const response = await axios.get(
);
dispatch({ type: 'SUCCESS', data: response.data });
} catch (e) {
dispatch({ type: 'ERROR', error: e });
}
};
useEffect(() => {
fetchUsers();
}, []);
useEffect는 페이지가 열렸을 때 처음에 괄호 안에 있는 함수를 실행시킵니다.
그래서 처음에는 Loading에 해당하는 동작을 하고
try문으로 진입해서 get요청을 한뒤 성공 여부에 따라서
SUCCESS나 ERROR 상태로 진행되게 됩니다.
오늘은 useAsync까지 공부해보려 했으나
리덕스를 배우면 사용하지 않을 것 같아서
짧게 마무리하겠습니다!
