728x90
반응형
src 디렉터리에 UserContext.js 라는 파일을 만들어보자.
UsersContext.js
import React, { createContext, useReducer, useContext } from 'react';
// UsersContext 에서 사용 할 기본 상태
const initialState = {
users: {
loading: false,
data: null,
error: null
},
user: {
loading: false,
data: null,
error: null
}
};
// 로딩중일 때 바뀔 상태 객체
const loadingState = {
loading: true,
data: null,
error: null
};
// 성공했을 때의 상태 만들어주는 함수
const success = data => ({
loading: false,
data,
error: null
});
// 실패했을 때의 상태 만들어주는 함수
const error = error => ({
loading: false,
data: null,
error: error
});
// 위에서 만든 객체 / 유틸 함수들을 사용하여 리듀서 작성
function usersReducer(state, action) {
switch (action.type) {
case 'GET_USERS':
return {
...state,
users: loadingState
};
case 'GET_USERS_SUCCESS':
return {
...state,
users: success(action.data)
};
case 'GET_USERS_ERROR':
return {
...state,
users: error(action.error)
};
case 'GET_USER':
return {
...state,
user: loadingState
};
case 'GET_USER_SUCCESS':
return {
...state,
user: success(action.data)
};
case 'GET_USER_ERROR':
return {
...state,
user: error(action.error)
};
default:
throw new Error(`Unhanded action type: ${action.type}`);
}
}
// State 용 Context 와 Dispatch 용 Context 따로 만들어주기
const UsersStateContext = createContext(null);
const UsersDispatchContext = createContext(null);
// 위에서 선언한 두가지 Context 들의 Provider 로 감싸주는 컴포넌트
export function UsersProvider({ children }) {
const [state, dispatch] = useReducer(usersReducer, initialState);
return (
<UsersStateContext.Provider value={state}>
<UsersDispatchContext.Provider value={dispatch}>
{children}
</UsersDispatchContext.Provider>
</UsersStateContext.Provider>
);
}
// State 를 쉽게 조회 할 수 있게 해주는 커스텀 Hook
export function useUsersState() {
const state = useContext(UsersStateContext);
if (!state) {
throw new Error('Cannot find UsersProvider');
}
return state;
}
// Dispatch 를 쉽게 사용 할 수 있게 해주는 커스텀 Hook
export function useUsersDispatch() {
const dispatch = useContext(UsersDispatchContext);
if (!dispatch) {
throw new Error('Cannot find UsersProvider');
}
return dispatch;
}
만약 id를 가지고 특정 사용자의 정보를 가져오는 API를 호출하고 싶으면 이런 형식으로 해줘야 한다.
dispatch({ type: 'GET_USER' });
try {
const response = await getUser();
dispatch({ type: 'GET_USER_SUCCESS', data: response.data });
} catch (e) {
dispatch({ type: 'GET_USER_ERROR', error: e });
}
API 처리 함수 만들기
이런 작업들을 처리하는 함수를 만들어보겠다. UserContext.js 파일을 열어서 하단에 함수들을 추가한다.
import React, { createContext, useReducer, useContext } from 'react';
import axios from 'axios';
// (...)
export async function getUsers(dispatch) {
dispatch({ type: 'GET_USERS' });
try {
const response = await axios.get(
'https://jsonplaceholder.typicode.com/users'
);
dispatch({ type: 'GET_USERS_SUCCESS', data: response.data });
} catch (e) {
dispatch({ type: 'GET_USERS_ERROR', error: e });
}
}
export async function getUser(dispatch, id) {
dispatch({ type: 'GET_USER' });
try {
const response = await axios.get(
`https://jsonplaceholder.typicode.com/users/${id}`
);
dispatch({ type: 'GET_USER_SUCCESS', data: response.data });
} catch (e) {
dispatch({ type: 'GET_USER_ERROR', error: e });
}
}
Context 사용하기
이제는 만든 Context를 사용해보자.
App.js
import React from 'react';
import Users from './Users';
import { UsersProvider } from './UsersContext';
function App() {
return (
<UsersProvider>
<Users />
</UsersProvider>
);
}
export default App;
Users.js
import React, { useState } from 'react';
import { useUsersState, useUsersDispatch, getUsers } from './UsersContext';
import User from './User';
function Users() {
const [userId, setUserId] = useState(null);
const state = useUsersState();
const dispatch = useUsersDispatch();
const { data: users, loading, error } = state.users;
const fetchData = () => {
getUsers(dispatch);
};
if (loading) return <div>로딩중..</div>;
if (error) return <div>에러가 발생했습니다</div>;
if (!users) return <button onClick={fetchData}>불러오기</button>;
return (
<>
<ul>
{users.map(user => (
<li
key={user.id}
onClick={() => setUserId(user.id)}
style={{ cursor: 'pointer' }}
>
{user.username} ({user.name})
</li>
))}
</ul>
<button onClick={fetchData}>다시 불러오기</button>
{userId && <User id={userId} />}
</>
);
}
export default Users;
useUserState로 state를 가져오고 useUserDispatch로 dispatch를 가져온다.
요청을 시작할 때 getUsers 안에 dispatch로 호출해준다.
실행해보면 정상작동 하는것을 볼 수 있다. 이번엔 User를 바꿔보자.
User.js
import React, { useEffect } from 'react';
import { useUsersState, useUsersDispatch, getUser } from './UsersContext';
function User({ id }) {
const state = useUsersState();
const dispatch = useUsersDispatch();
useEffect(() => {
getUser(dispatch, id);
}, [dispatch, id]);
const { data: user, loading, error } = state.user;
if (loading) return <div>로딩중..</div>;
if (error) return <div>에러가 발생했습니다</div>;
if (!user) return null;
return (
<div>
<h2>{user.username}</h2>
<p>
<b>Email:</b> {user.email}
</p>
</div>
);
}
export default User;
useEffect()를 사용해서 id값이 바뀔 때마다 getUser() 함수를 호출해준다. 두번째 파라미터에 props로 받아온 id값을
넣어준다.
정리
- Provider를 만들고 state와 dispatch를 선언하고, userReducer와 initialState를 지정해준다.
- state와 dispatch를 Provider로 감싼 내부에서 사용할 수 있도록 Context를 구현한다.
- 그 밖에 dispatch를 이용한 함수들을 구현한다.
- state의 공유가 필요한 곳을 provider로 감싼다.
- 감싸여진 컴포넌트에서 state,dispatch, 함수들을 import 해준다.
- 감싸여진 컴포넌트에 할당된 값이 바뀔 때마다 변환을 해주려면 useEffect를 써준다.
728x90
반응형
'Front-End > React.js' 카테고리의 다른 글
React.js | CSS, SASS, SCSS (0) | 2021.11.02 |
---|---|
React.js | API 연동 | 마지막 (0) | 2021.10.08 |
React.js | API 연동 | react-async로 요청 상태 관리하기 (0) | 2021.10.07 |
React.js | API 연동 | useAsync 커스텀 Hook (0) | 2021.10.07 |
React.js | API 연동 | useReducer로 요청 상태 관리하기 (0) | 2021.10.07 |