일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- 엑셀필터복사붙여넣기
- TACKING
- 자켓실측
- 비리짐
- 웹API
- 암홀트롭
- 미니마카
- 40HQ컨테이너
- MERN스택
- 헤이큐
- Armhole Drop
- AATCC
- 슈퍼코딩
- 우레탄지퍼
- WHATTIMEOFTHEDAY
- 40HQ컨테이너40GP컨테이너차이
- 필터링후복사붙여넣기
- 클린코드
- 지연환가료
- 비슬론지퍼
- 봉제용어
- 미국영어연음
- 엑셀드래그단축키
- 영어시간읽기
- 와끼
- 나일론지퍼
- 핸드캐리쿠리어차이점
- 고급영어단어
- 엑셀자동서식
- 요척합의
- Today
- Total
CASSIE'S BLOG
상태관리 라이브러리인 Redux를 React 환경해서 사용하는 방법 본문
Redux 설치
npm 명령어를 통해서 라이브러리를 설치해줍니다. 리액트에서 redux 라이브러리를 더 효율적으로 사용할 수 있는 react-redux 라이브러리도 설치하겠습니다.
npm install redux
npm install react-redux
스토어(reducer)
리덕스에서는 Store라는 상태 저장소를 사용합니다. 이 Store에서 관리되는 상태 값은 일반적인 방법으로 꺼내오거나 변경하는 것이 불가능하며, 정해진 방식을 통해서만 가져오거나 변경할 수 있습니다. 이러한 방식을 사용하는 이유는 Store 내부의 상태값의 안정성을 유지하기 위함입니다.
리덕스에서는 Action → Dispatch → Reducer → Store 순서로 데이터가 단방향으로 흐르게 됩니다. 각 단계를 코드로 구현해보도록 하겠습니다.
redux 라이브러리에서 createStore 메소드를 통해서 Store 객체를 생생해 줍니다. 그리고 react-redux 라이브러리에서 Provider 컴포넌트를 가져와 우리가 스토어를 통해 상태를 관리해줄 컴포넌트를 감싸주면 됩니다. 전역적으로 상태를 관리하기 위해서 App 컴포넌트를 감싸줍니다.
여기까지 한다면 상태 저장소를 만들고 전역 상태에서 관리하기 위한 준비를 마친 것 입니다.
// index.js
import React from "react";
import { createRoot } from "react-dom/client";
import App from "./App";
import { Provider } from "react-redux";
import { createStore } from "redux";
const rootElement = document.getElementById("root");
const root = createRoot(rootElement);
const store = createStore();
root.render(
<Provider store={store}>
<App />
</Provider>
);
리듀서(Reducer)
이번에는 상태를 변경시키는 reducer에 대해 대해서 알아보겠습니다. reducer 함수는 첫 번째 매개변수로 현재 state값을 받고 두번째 매개변수로 action이라는 객체를 받습니다. 그리고 전달받은 action에 따라 state 값을 변경시킵니다.
아래의 코드를 보면 action 객체의 type에 따라서 state 값을 증가하가나 감소시키고 정해진 action 객체가 아니면 기본값으로 기존의 state를 그대로 리턴해 줍니다. reducer 함수의 내부 로직에 따라 다양한 방식으로 state 값을 변경 시킬 수 있습니다.
reducer 함수를 생성한 후에 createStore에 전달해주면 전달받은 reducer 함수를 통해 상태를 변경할 준비를 마친 것 입니다.
// index.js
import React from "react";
import { createRoot } from "react-dom/client";
import App from "./App";
import { Provider } from "react-redux";
import { createStore } from "redux";
const count = 1;
// reducer 생성
const reducer = (state = count, action) => {
switch (action.type) {
//action === 'INCREASE'일 경우
case "INCREASE":
return state + 1;
// action === 'DECREASE'일 경우
case "DECREASE":
return state - 1;
// action === 'SET_NUMBER'일 경우
case "SET_NUMBER":
return action.payload;
// 해당 되는 경우가 없을 땐 기존 상태를 그대로 리턴
default:
return state;
}
const rootElement = document.getElementById("root");
const root = createRoot(rootElement);
const store = createStore(reducer);
root.render(
<Provider store={store}>
<App />
</Provider>
};
액션(Action)
이번에는 reducer 함수로 전달되는 action 객체에 대해 알아보겠습니다. action 객체는 필수적으로 type이라는 키를 가지고 그 외에 필요한 데이터를 payload로 가집니다.
// [예시]
// payload가 필요 없는 경우
const action = {
type : "INCREASE"
}
// payload가 필요한 경우
const action = {
type : "INCREASE",
payload : 10;
}
액션 객체는 직접 작성해도 함수를 사용하여 리턴해주는 방법도 있습니다. 이번에는 action 객체를 리턴하는 함수를 만들어서 다른 컴포넌트에서 사용할 수 있도록 export 해주도록 하겠습니다.
// index.js
import React from "react";
import { createRoot } from "react-dom/client";
import App from "./App";
import { Provider } from "react-redux";
import { createStore } from "redux";
//action 객체를 리턴하는 함수 생성
export const increase = () => {
return {
type: "INCREASE"
};
};
export const decrease = () => {
return {
type: "DECREASE"
};
};
const count = 1;
// reducer 생성
const reducer = (state = count, action) => {
switch (action.type) {
//action === 'INCREASE'일 경우
case "INCREASE":
return state + 1;
// action === 'DECREASE'일 경우
case "DECREASE":
return state - 1;
// action === 'SET_NUMBER'일 경우
case "SET_NUMBER":
return action.payload;
// 해당 되는 경우가 없을 땐 기존 상태를 그대로 리턴
default:
return state;
}
const rootElement = document.getElementById("root");
const root = createRoot(rootElement);
const store = createStore(reducer);
root.render(
<Provider store={store}>
<App />
</Provider>
};
디스패치(Dispatch)
dispatch는 reducer로 action 객체를 전달하는 역할을 합니다.
// [예시]
const action = {type:"DECREASE", payload:5};
dispatch({type:"INCREASE", payload:5}); // reducer 함수로 {type:"INCREASE", payload:5} 전달
dispatch(action); // reducer 함수로 {type:"DECREASE", payload:5} 전달
react-redux 라이브러리는 action 객체를 reducer에 전달하고 변경된 state의 변경사항을 다른 컴포넌트에게 알려주는 역할을 하는 hooks를 지원합니다. useDisptch로 action 객체를 전달하고 useSelector를 통해 변경된 state를 가져올 수 있습니다.
아래의 코드에서 버튼을 눌려서 함수를 실행 시키면 함수 내부의 dispatch 함수가 increase 또는 decrease 함수가 리턴한 action 객체을 reducer 함수로 전달합니다.
// App.js
import React from "react";
import { useDispatch, useSelector } from "react-redux";
import { increase, decrease } from "./index";
export default function App() {
// store 객체의 dispatch 역할
const dispatch = useDispatch(); // store의 dispatch 함수 사용
// store 객체의 getState() 역할
const state = useSelector((state) => state); // store에 있는 state 값을 가져오는 역할
const plusNum = () => {
dispatch(increase());
};
const minusNum = () => {
dispatch(decrease());
};
return (
<div className="container">
<h1>{`Count: ${state}`}</h1>
<div>
<button className="plusBtn" onClick={plusNum}>
+
</button>
<button className="minusBtn" onClick={minusNum}>
-
</button>
</div>
</div>
);
}
리듀서(Reducer)가 여러개인 경우
프로젝트가 커지면서 다루어야하는 상태값이 많아 질경우 로직에 따라서 여러가지 reducer를 사용해야하는 경우 combineReducers를 사용할 수 있습니다. 아래는 todoApp을 만드는 애플리케이션의 예시 코드입니다.
우선 reducer로 전달할 action 객체를 리턴하는 함수들을 정의하고 export 합니다.
// action.js
export const ADD_TODO = "ADD_TODO";
export const COMPLETE_TODO = " COMPLETE_TODO ";
export const SHOW_ALL = "SHOW_ALL";
export const SHOW_COMPLETE = "SHOW_COMPLETE";
// {type : ADD_TODO, text : '할일'}
export function addTodo(text) {
return {
type: ADD_TODO,
text: text,
};
}
//{type: COMPLETE_TODO,. index : 3}
export function completeTodo(index) {
return {
type: SHOW_ALL,
index: index,
};
}
//{type: COMPLETE_TODO,. index : 3}
export function showCompletel() {
return {
type: SHOW_COMPLETE,
};
}
export function showAll() {
return {
type: SHOW_ALL,
};
}
combineReducers를 이용하여 todos와 filter라는 두 가지 reducer를 결합할 수 있습니다. 전달된 action의 type값이 무엇이냐에 따라 todos 또는 filter 중 해당하는 reducer 함수로 전달되어 state값을 변경시킵니다.
// reducer.js
import { combineReducers } from "redux";
import todos from "./todos";
import filter from "./filter";
const reducer = combineReducers({ todos: todos, filter: filter });
export default reducer;
action.type 값이 ADD_TODO 또는 COMPLETE_TODO 인경우 todos reducer가 동작합니다.
// todos.js
import { ADD_TODO, COMPLETE_TODO } from "./actions";
const initialState = [];
// todosInitialState = [{text : '코딩', done : false}, {text : '점심먹기', done : false}]
export default function todos(previousState = initialState, action) {
if (action.type === ADD_TODO) {
return [...previousState, { text: action.text, done: false }];
}
if (action.type === COMPLETE_TODO) {
return previousState.todos.map((todo, index) => {
if (index === action.index) {
return { ...todo, done: true };
}
return todo;
});
}
return previousState;
}
action.type 값이 SHOW_ALL 또는 SHOW_COMPLETE 인경우 filter reducer가 동작합니다.
// filter.js
import { SHOW_ALL, SHOW_COMPLETE } from "./actions";
const initialState = "ALL";
export default function filter(previousState = initialState, action) {
if (action.type === SHOW_COMPLETE) {
return "COMPLETE";
}
if (action.type === SHOW_ALL) {
return "ALL";
}
return previousState;
}
위의 코드처럼 기능에 따른 reducer를 나누어서 작성하면 코드를 유지보수하는데 효율적입니다.
출처:
'PROGRAMMING > React' 카테고리의 다른 글
Gulp.js vs Webpack (0) | 2023.10.09 |
---|---|
Trailing Comma 후행 콤마 (0) | 2023.10.09 |
line-height (텍스트 요소 내에서 행 사이의 수직 간격을 조절하는 데 사용) (0) | 2023.10.09 |
@media, 768px, 투명도 `10% (0) | 2023.10.09 |
[비공개] 원본... (1) | 2023.10.09 |