[React] ContextAPI๋ฅผ ์ฌ์ฉํด์ TodoList๋ง๋ค๊ธฐ(2) : contextAPI
contextAPI์ ๋ํด์๋ ์ฑ ๐๋ฆฌ์กํธ๋ฅผ ๋ค๋ฃจ๋ ๊ธฐ์ ๐์์๋ ๋ค๋ค์ง๋ง ๊ฒ์ผ๋ก๋ ์ดํดํ์ง๋ง, ๋ชธ๊ณผ ๋ง์ ์ ์ฒด์ ์ผ๋ก ์์ง ์ดํด๋ฅผ ๋ชปํ๊ณ ๊นจ๋ซ์ง ๋ชปํ๋ค๋ ์๊ฐ์ด ๋ค์ด์ contextAPI๋ฅผ ์ฌ์ฉํ ์์ ์ธ ํฌ๋๋ฆฌ์คํธ๋ฅผ ์ฐพ์์ ๋ค์ํด๋ณด๊ฒ ๋์๋ค.
์ด๋ฒ ํฌ์คํธ๋ฅผ ์ฐ๋ฉด์ ์ ํ ๋ด ๋ชฉํ๋ ์ด ํฌ์คํธ๋ฅผ ์ฐ๋ฉด์ ๋ค ์ฐ๊ณ ๋์๋ ๋ด๊ฐ contextAPI๊ฐ ๋ญ์ง ์ ๋๋ก ์ค๋ช ํ ์ ์๊ณ ์ ์ ์๋๋ก ๋ง๋๋ ๊ฒ์ด๋ค.
์ด์ ํฌ์คํธ๋ ์ด ํฌ๋๋ฆฌ์คํธ๋ฅผ ๋ง๋ค๋ฉด์ ์ฌ์ฉํ styled-components์ ๋ํ ์์๋ค์ ๊ณต๋ถํด๋ณธ ํฌ์คํธ์ด๋ค.
์ด ๊ธ์ ๊ณต์๋ฌธ์์ ๋ฒจ๋กํผํธ๋์ contextAPI๋ฅผ ์ฌ์ฉํ ํฌ๋๋ฆฌ์คํธ ๋ง๋ค๊ธฐ๋ฅผ ์ฐธ๊ณ ํ์ฌ ์์ฑํ ๊ธ์ ๋๋ค.
Context
context๋ฅผ ์ด์ฉํ๋ฉด ๋จ๊ณ๋ง๋ค ์ผ์ผ์ด props๋ฅผ ๋๊ฒจ์ฃผ์ง ์๊ณ ๋ ์ปดํฌ๋ํธ ํธ๋ฆฌ ์ ์ฒด์ ๋ฐ์ดํฐ๋ฅผ ์ ๊ณตํด์ค๋ค.
์ผ๋ฐ์ ์ผ๋ก๋ ๋ถ๋ชจ๊ฐ ์์์๊ฒ props๋ฅผ ์ ๋ฌํ์ง๋ง, ์ปดํฌ๋ํธ๊ฐ ์ฌ๋ฌ๊ฐ๊ฐ ๋๊ณ ๋ณต์กํด์ง๋ฉด์ ์ด ๊ณผ์ ์ด ๋ฒ๊ฑฐ๋ก์์ง๋๋ค. ์ด ๊ณผ์ ์์ context๋ฅผ ์ฌ์ฉํ๋ฉด ๋ ๊ฐ๋จํ๊ฒ ๊ตฌํํด์ค ์ ์์ต๋๋ค.
์ฒ์์ ๋ง๋ค์๋ ์ฝ๋๋ App ์์ todos ์ํ์, onToggle, onRemove, onCreate ํจ์๋ฅผ ์ง๋๊ณ ์๊ฒ ํ๊ณ , ํด๋น ๊ฐ๋ค์ props ๋ฅผ ์ฌ์ฉํด์ ์์ ์ปดํฌ๋ํธ๋ค์๊ฒ ์ ๋ฌํด์ฃผ๋ ๋ฐฉ์์ผ๋ก ๊ตฌํํ๋ค.
์ง๊ธ์ ์ด๋ ๊ฒ ๊ตฌํํด๋ ๋ฌธ์ ๊ฐ ์์ง๋ง, ํ๋ก์ ํธ์ ๊ท๋ชจ๊ฐ ์ปค์ง๊ณ ๋ณต์กํด์ง๋ค๋ฉด props๋ฅผ ์ ๋ฌํด์ค์ผํ๋ ์ปดํฌ๋ํธ๊ฐ ๋์ด์ด์ด๋ฌด ๊น์ํ ์๊ฒ ๋ ์ ์๋ค.
๊ทธ๋ ๊ฒ ๋๋ฉด ๋๋ฌด ๋ณต์กํด์ง๊ธฐ ๋๋ฌธ์ context๋ฅผ ์ฌ์ฉํด์ ์๋ ์ฌ์ง๊ณผ ๊ฐ์ด ๊ตฌํํ ์ ์๋ค.
Context๋ฅผ ์ฌ์ฉํด์ ์ ์ญ ๋ฒ์๋ก state๋ฅผ ๊ด๋ฆฌํ ์ ์๊ธฐ ๋๋ฌธ์ ๊ฐ ์ปดํฌ๋ํธ์์ Direct Access ๊ฐ๋ฅ
๐ค์ฌ๊ธฐ์ ์ ๊น! dispatch๊ฐ ๋ญ์ง?
๋ฆฌ๋์ค์ ๋ํ ํฌ์คํธ๋ ๋์ค์ ๋ค์ ๋ค๋ค๋ณผ ์์ ์ธ๋ฐ dispatch๊ฐ ๋ญ์ง ์ฌ๊ธฐ์ ๋จผ์ ๊ฐ๋จํ ์ง๊ณ ๋์ด๊ฐ์ผ๊ฒ ๋ค!
dispatch์ ๋ํด์๋ useReducer์์๋ ์ธ๊ธ์ด ๋์์๋ค.
const [state, dispatch] = useReducer(reducer, initialArg, init);
useReducer๋ useState์ ๋์ฒดํจ์๋ก, (state, action)=>newState์ ํํ๋ก reducer๋ฅผ ๋ฐ๊ณ dispatch ๋ฉ์๋์ ์ง ํํ๋ก ํ์ฌ state๋ฅผ ๋ฐํํ๋ค.
๋์คํจ์น๋ ์ก์ ์ ๋ฐ์์ํค๋ ์ญํ ์ ํ๋ค.
์ก์ ์ ๋ฐ์์์ผ์ ์คํ ์ด์๊ฒ ์ํ๋ณํ๊ฐ ํ์ํ๋ค๋ ๊ฒ์ ์๋ ค์ค๋ค!
๊ทธ๋ ๊ฒ ํธ์ถ๋ ์ก์ ์ useReducerํจ์๋ฅผ ํธ์ถ์ํค๊ณ ์ํ๋ฅผ ๋ณํ์ํค๋ ๊ณผ์ ์ ๊ฑฐ์น๊ฒ ๋๋ค.
์ํ๊ด๋ฆฌ๋ฅผ ์ํ ๊ฒ์ด๋ผ๊ณ ๊ฐ๋จํ ์ดํดํ์!
์ผ๋จ ๊ฐ๋จํ ์ดํด๋ ์ฌ๊ธฐ๊น์งํ๊ณ ๋ค์ ์ฝ๋๋ก ๋์์๋ณด๊ฒ ๋ค.
์์ธํ ๋ด์ฉ์ ๋ฆฌ๋์ค๋ฅผ ์ ๋ฆฌํ ๊ธ์ ํฌ์คํธํ๋ฉด์ ์ ๋ฆฌํ๊ฒ ๋ค!!
์ด ์ฝ๋์์๋ state ์ dispatch ๋ฅผ Context ํตํ์ฌ ๋ค๋ฅธ ์ปดํฌ๋ํธ์์ ๋ฐ๋ก ์ฌ์ฉ ํ ์ ์๊ฒ ํด์คํ ๋ฐ, ์ฐ๋ฆฌ๋ ํ๋์ Context ๋ฅผ ๋ง๋ค์ด์ state ์ dispatch ๋ฅผ ํจ๊ป ๋ฃ์ด์ฃผ๋ ๋์ ์, ๋๊ฐ์ Context ๋ฅผ ๋ง๋ค์ด์ ๋ฐ๋ก ๋ฐ๋ก ๋ฃ์ด์ค๋ค. ์ด๋ ๊ฒ ํ๋ฉด dispatch ๋ง ํ์ํ ์ปดํฌ๋ํธ์์ ๋ถํ์ํ ๋ ๋๋ง์ ๋ฐฉ์ง ํ ์ ์์ต๋๋ค. ์ถ๊ฐ์ ์ผ๋ก, ์ฌ์ฉํ๊ฒ ๋๋ ๊ณผ์ ์์ ๋์ฑ ํธ๋ฆฌํ๋ค๊ณ ํ๋ค.
TodoContext.js
import React, { useReducer, createContext, useContext, useRef } from 'react';
const initialTodos = [
{
id: 1,
text: 'ํ๋ก์ ํธ ์์ฑํ๊ธฐ',
done: true
},
{
id: 2,
text: '์ปดํฌ๋ํธ ์คํ์ผ๋งํ๊ธฐ',
done: true
},
{
id: 3,
text: 'Context ๋ง๋ค๊ธฐ',
done: false
},
{
id: 4,
text: '๊ธฐ๋ฅ ๊ตฌํํ๊ธฐ',
done: false
}
];
function todoReducer(state, action) {
switch (action.type) {
case 'CREATE':
return state.concat(action.todo);
case 'TOGGLE':
return state.map(todo =>
todo.id === action.id ? { ...todo, done: !todo.done } : todo
);
case 'REMOVE':
return state.filter(todo => todo.id !== action.id);
default:
throw new Error(`Unhandled action type: ${action.type}`);
}
}
const TodoStateContext = createContext();
const TodoDispatchContext = createContext();
const TodoNextIdContext = createContext();
export function TodoProvider({ children }) {
const [state, dispatch] = useReducer(todoReducer, initialTodos);
const nextId = useRef(5);
return (
<TodoStateContext.Provider value={state}>
<TodoDispatchContext.Provider value={dispatch}>
<TodoNextIdContext.Provider value={nextId}>
{children}
</TodoNextIdContext.Provider>
</TodoDispatchContext.Provider>
</TodoStateContext.Provider>
);
}
export function useTodoState() {
return useContext(TodoStateContext);
}
export function useTodoDispatch() {
return useContext(TodoDispatchContext);
}
export function useTodoNextId() {
return useContext(TodoNextIdContext);
}
context์์ ์ฌ์ฉํ ๊ฐ์ ์ง์ ํ๊ธฐ ์ํด์๋ Provider์ปดํฌ๋ํธ๋ฅผ ๋ ๋๋งํ๊ณ value๋ฅผ ์ ํด์ฃผ๋ฉด๋๋ค.
<TodoDispatchContext.Provider value={dispatch}>
{children}
</TodoDispatchContext.Provider>
์ด ์ฝ๋์ฒ๋ผ๋ง์ด๋ค.
๊ทธ๋ฆฌ๊ณ props๋ก ๋ฐ์์จ children๊ฐ์ ๋ด๋ถ์ ๋ ๋๋งํด์ฃผ๋ฉด ๋๋ค.
TodoContext ์ฝ๋๋ useConext๋ฅผ 3๊ฐ๋ก ๋ถ๋ฆฌํ๋ค.(State, Dispatch, nextId)
useContext๋ก ํด๋น context๋ฅผ ๋ฃ์ด์ค๋ค.
import { useTodoState } from '../TodoContext';
import { useTodoDispatch } from '../TodoContext';
...
/* ์ปค์คํ
์ ์ฉ : ์ปค์คํ
ํ ํจ์๋ก ๋ฐ๋ก ์ฌ์ฉ ๊ฐ๋ฅ */
const todos = useTodoState();
const dispatch = useTodoDispatch();
/* ์ปค์คํ
๋ฏธ์ ์ฉ : Context์์ฒด๋ฅผ useContext์ ์ธ์๋ก ๋ฃ์ */
const todos = useContext(TodoStateContext);
const dispatch = useContext(TodoDispatchContext);
useTodoState, useTodoDispatch๋ฑ์ ์ฌ์ฉํ ๋, useContext ๋ฅผ ์ฌ์ฉํ๋ ์ปค์คํ Hook ์ ๋ง๋ค์ด์ ๋ด๋ณด๋ด์ฃผ๋ ๋ฐฉ๋ฒ๊ณผ ์ปค์คํ ํ ํจ์๋ฅผ ๋ฐ๋ก ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ 2๊ฐ์ง๊ฐ ์๋๋ฐ ์์ ์ฝ๋์ ๊ฐ์ด ์ปค์คํ ์ ์ ์ฉํ๊ณ ์ํ๊ณ ์ ๋ฐ๋ผ ๋ฌ๋ผ์ง๋ค.
์์ ํ ๋ค ์ดํดํด๋ณด๋ ค๊ณ ํ๋๋ฐ ์์ง ๋ถ์กฑํ๊ฒ๋ง ๋๊ปด์ง๋ค. ๋นจ๋ฆฌ ๋ฆฌ๋์ค ๊ด๋ จ ํฌ์คํธ๋ฅผ ์ฌ๋ ค์ ๋ ์๋ฒฝํ ์ดํดํ ์ ์๋๋ก ํด์ผ๊ฒ ๋ค๊ณ ์๊ฐํ๊ฒ ๋๋ค.๐ฅ