상태를 관리하게 될 때 useState 를 사용하는것 말고도 useReducer 를 사용할 수 있습니다. useReducer 를 사용하면 컴포넌트의 상태 업데이트 로직을 컴포넌트에서 분리시킬 수 있습니다. 상태 업데이트 로직을 컴포넌트 바깥에 작성 할 수도 있고, 심지어 다른 파일에 작성 후 불러와서 사용 할 수도 있습니다.
const [state, dispatch] = useReducer(reducer, initialState);
function reducer(state, action) {
// 새로운 상태를 만드는 로직
// const nextState = ...
return nextState;
}
state는 컴포넌트에서 사용 할 수 있는 상태를 가르키게 되고, dispatch 는 액션을 발생시키는 함수입니다. useReducer 에 넣는 첫번째 parameter 는 reducer 함수이고, 두번째 parameter 는 초기 상태입니다. reducer 는 현재 state 와 action 객체를 파라미터로 받아와서 새로운 상태를 반환해주는 함수입니다. 여기서 action 은 업데이트를 위한 정보를 가지고 있습니다.
import React, { useReducer } from "react";
const initialState = 0;
const reducer = (state, action) => {
switch (action.type) {
case "DECRESE":
return state - 1;
case "INJCRESE":
return state + 1;
case "RESET":
return initialState;
default:
return state;
}
};
const Counter = () => {
/*
dispatch는 액션을 발생시키는 함수
*/
const [count, dispatch] = useReducer(reducer, initialState);
return (
<>
<h1>숫자세기</h1>
<p>{count}</p>
<button onClick={() => dispatch({ type: "DECRESE" })}>-</button>
<button onClick={() => dispatch({ type: "INJCRESE" })}>+</button>
<button onClick={() => dispatch({ type: "RESET" })}>reset</button>
</>
);
};
export default Counter;
이렇게 useReducer를 사용함으로써 state를 reducer 함수를 통해 분리하여 관리가 가능합니다.
Redux는 React 생태계에서 가장 사용률이 높은 상태관리 라이브러리입니다. Redux를 사용하면 컴포넌트들의 상태 관련 로직들을 다른 파일들로 분리시켜서 더욱 효율적으로 관리 할 수 있으며 글로벌 상태 관리도 손쉽게 할 수 있습니다. 또한 Redux는 React 뿐만 아니라 VUE 와도 잘 결합되며, 또한 순수 JS와도 결합이 됩니다.
하나의 애플리케이션 안에는 하나의 Store
하나의 애플리케이션에선 단 한개의 Store 를 만들어서 사용합니다. 여러 개의 Store 를 사용하는 것은 사실 가능하지만 권장하지 않습니다.
State 는 읽기전용
useState 처럼 Redux 에서도 기존의 State 는 건들이지 않고 새로운 State 를 생성하여 업데이트를 해주는 방식으로 합니다. Redux 에서 불변성을 유지해야 하는 이유는 내부적으로 데이터가 변경 되는 것을 감지하기 위해서 입니다.
변화를 일으키는 함수, Redux 는 순수한 함수
Redux 함수는 이전 State 와 액션 객체를 파라미터로 받습니다.
이전의 State는 절대로 건들이지 않고, 변화를 일으킨 새로운 State 객체를 만들어서 반환합니다.
React에서 Redux를 사용하기위해 "react-redux", Redux를 효율적으로 사용하기 위해 "@reduxjs/toolkit"와 "redux-logger" 라이브러리 설치를 통해 실습을 했습니다.
import { createSlice } from "@reduxjs/toolkit";
const initialState = [];
const todoSlice = createSlice({
name: "Todo",
initialState,
reducers: {
addTodoStore(state, action) {
return [...state, { ...action.payload }];
},
removeTodoStore(state, action) {
return state.filter((todo) => todo.id !== action.payload);
},
clearTodoStore(state, action) {
return state.forEach((todo) => {
if (todo.id === action.payload) {
todo.clear = !todo.clear;
}
});
},
},
});
export const { addTodoStore, removeTodoStore, clearTodoStore } =
todoSlice.actions;
export default todoSlice.reducer;
"@reduxjs/toolkit"의 createSlice 함수를 사용하여 reducer와 action을 만들 수 있습니다.
import { configureStore } from "@reduxjs/toolkit";
import todoSlice from "./todoSlice";
import logger from "redux-logger";
const store = configureStore({
reducer: {
TodoStore: todoSlice,
},
middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(logger),
});
export default store;
"@reduxjs/toolkit"의 configureStore 함수를 사용하여 store를 생성할 수 있습니다. store에는 createSlice를 통해 만든 reducer를 넣어 사용할 수 있습니다.
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import { Provider } from "react-redux";
import store from "./redux/store";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>
);
Redux를 전역으로 사용하기 위해 "react-redux"의 Proveider 에 만들어준 store를 넣어 컴포넌트를 감싸줍니다.
import React, { useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import {
addTodoStore,
clearTodoStore,
removeTodoStore,
} from "../redux/todoSlice";
const ReduxTodo = () => {
const dispatch = useDispatch();
const todos = useSelector((state) => state.TodoStore);
const [value, setValue] = useState("");
const addTodo = (event) => {
event.preventDefault();
dispatch(addTodoStore({ todo: value, id: Date.now(), clear: false }));
setValue("");
};
return (
<>
<h1>할 일 목록</h1>
<ul>
{todos.map((todo) => (
<li key={todo.id}>
<span style={{ textDecoration: todo.clear && "line-through " }}>
{todo.todo}
</span>
<button onClick={() => dispatch(clearTodoStore(todo.id))}>✔</button>
<button onClick={() => dispatch(removeTodoStore(todo.id))}>
❌
</button>
</li>
))}
</ul>
<form onSubmit={addTodo}>
<input
type="text"
value={value}
onChange={(event) => setValue(event.target.value)}
/>
<input type="submit" value={"추가하기"} />
</form>
</>
);
};
export default ReduxTodo;
Resuc의 state를 관리하기 위해서는 "react-redux"의 useDispatch 와 useSelector를 사용합니다. useDispatch는 export한 action을 이용하여 state를 변경할 수 있습니다. useSelector는 store의 reducer를 선택하여 컴포넌트에 state를 사용할 수 있습니다.
상태를 웹 전역에서 관리하고 사용할 수 있는 Redux를 배웠습니다. 덕분에 React 웹을 개발하는데 생겼던 불편한 부분을 효율적으로 관리할 수 있었습니다. 뿐만 아니라 더 다양한 기능을 추가할 수 있어 보였습니다. 이렇듯 점점 서비스가 가능한 웹에 가까워지는 작업물을 보니 개발자에 한걸음 더 가까워진것 같습니다.
#프로젝트캠프 #프로젝트캠프후기 #유데미 #스나이퍼팩토리 #웅진씽크빅 #인사이드아웃 #IT개발캠프 #개발자부트캠프 #리액트 #react #부트캠프 #리액트캠프