들어가기에 앞서
리덕스란?
리덕스는 자바스크립트 어플리케이션 상태관리 라이브러리 이다. 특히 React와 함께 사용될때 유용하지만 다른 라이브러리와 프레임워크와도 사용이 가능하다.
리덕스는 하나의 상태를 하나의 저장소로 관리하며 이 저장소에 저장된 상태는 직접 수정이 불가능하고 오직 액션을 통해서만 변경될 수 있다. 액션은 상태 변경을 위한 명령어이며 어플리케이션에서 발생하는 모든 상태 변경은 이러한 액션을 통해 이루어진다. 액션을 처리하기 위해서는 리듀서를 이용해 이전 상태와 액션을 받아 새로운 상태를 반환하는 순수함수이다.
리덕스는 단방향 데이터 흐름을 따르기 때문에 상태 변화를 예측하기 쉽고, 디버깅도 용이하다. 또한 여러 컴포넌트 간의 상태를 공유하거나 상태 변경 로직을 중앙 집중화하여 관리하기 때문에 코드 유지보수성을 높여준다.
Redux 상태 관리 순서
1. 상태가 변경되어야 하는 이벤트가 발생하면, 변경될 상태에 대한 정보가 담긴 Action 객체 생성
2. Action객체는 Dispatch함수의 단일인자로 전달된다.
3. Dispatch함수는 Action 객체를 Reducer함수로 전달한다.
4. Reducer함수는 Action객체의 값을 확인해서 전역 상태 저장소 Store의 상태를 변경한다.
5. 상태가 변하면 React는 리렌더링을 한다.
1. Store
- Redux앱의 state가 관리되는 오직 하나뿐인 저장소
// 1
import { Provider } from 'react-redux';
// 2
import { legacy_createStore as createStore } from 'redux';
const rootElement = document.getElementById('root');
const root = createRoot(rootElement);
const count = 1;
const reducer = () => {};
// 4
const store = createStore(reducer);
root.render(
// 3
<Provider store={store}>
<App />
</Provider>
);
👇🏻 자세한 구현사항
1. Provider는 store를 쉽게 사용할 수 있게 하는 컴포넌트이다. 해당 컴포넌트를 불러온 다음에, Store를 사용할 컴포넌트를 감싸준 후 Provider 컴포넌트의 props로 store를 설정한다.
import { Provider } from 'react-redux';
2. redux에서 createStore를 불러온다.
import { legacy_createStore as createStore } from 'redux';
3. 전역 상태 저장소 store를 사용하기 위해서는 App 컴포넌트를 Provider로 감싸준 후 props로 변수 store를 전달해주어야 한다.
<Provider store={store}>
<App />
</Provider>
4. 변수 store에 createStore 메서드를 통해 store를 만들어준다.
const store = createStore(reducer);
2. Reducer
- Dispatch에서 전달받은 Action 객체의 type값에 따라서 상태를 변경시키는 함수
// 1
const count = 1
// Reducer를 생성할 때에는 초기 상태를 인자로 요구합니다.
const counterReducer = (state = count, action) => {
// Action 객체의 type 값에 따라 분기하는 switch 조건문입니다.
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;
}
}
// Reducer가 리턴하는 값이 새로운 상태가 됩니다.
// 2
const store = createStore(counterReducer);
root.render(
// 3
<Provider store={store}>
<App />
</Provider>
);
👇🏻 자세한 구현사항
1. Dispatch에서 전달받은 Action 객체의 type에 따라서 상태를 변경시키는 순수함수인 Reducer 함수 생성
const count = 1
// Reducer를 생성할 때에는 초기 상태를 인자로 요구합니다.
const counterReducer = (state = count, action) => {
// Action 객체의 type 값에 따라 분기하는 switch 조건문입니다.
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;
}
}
// Reducer가 리턴하는 값이 새로운 상태가 됩니다.
2. 1에서 가져온 Reducer함수를 createStore함수 인자로 넣어준다.
const store = createStore(counterReducer);
3. 상태저장소 사용하기위해 props로 2번의 변수 store를 넘겨준다.
root.render(
// 3
<Provider store={store}>
<App />
</Provider>
);
3. Action
- 어떤 action을 취할 것인지 정의해 놓은 type이 필수로 지정된 객체
- 보통 Action 객체를 생성하는 함수 Action Creator를 만들어 사용
import React from 'react';
import { createRoot } from 'react-dom/client';
import App from './App';
import { Provider } from 'react-redux';
import { legacy_createStore as createStore } from 'redux';
const rootElement = document.getElementById('root');
const root = createRoot(rootElement);
const count = 1;
// Reducer를 생성할 때에는 초기 상태를 인자로 요구합니다.
const counterReducer = (state = count, action) => {
// Action 객체의 type 값에 따라 분기하는 switch 조건문입니다.
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;
}
// Reducer가 리턴하는 값이 새로운 상태가 됩니다.
};
// 1
export const increase = () => {
return {
type: 'INCREASE',
};
};
// 2
export const decrease를 = () => {
return {
type: 'DECREASE',
};
};
const store = createStore(counterReducer);
root.render(
<Provider store={store}>
<App />
</Provider>
);
👇🏻 자세한 구현사항
1. Action 함수 increase를 만든다.
export const increase = () => {
return {
type: 'INCREASE',
};
};
2.Action함수 decrease를 만든다.
export const decrease를 = () => {
return {
type: 'DECREASE',
};
};
3. 1,2 함수를 다른 파일에서도 사용할 수 있게 export를 붙여준다.
4. Dispatch
- Action객체를 Reducer로 전달해주는 함수
// Action 객체를 직접 작성하는 경우
dispatch( { type: 'INCREASE' } );
dispatch( { type: 'SET_NUMBER', payload: 5 } );
// 액션 생성자(Action Creator)를 사용하는 경우
dispatch( increase() );
dispatch( setNumber(5) );
5. Redux Hooks
1. useDispatch()
- Action 객체를 Reducer로 전달해주는 Dispatch함수를 반환하는 메서드
// 1
import { useDispatch } from 'react-redux';
// 2
import { increase, decrease } from './index.js';
export default function App() {
// 3
const dispatch = useDispatch();
console.log(dispatch);
const plusNum = () => {
// 4
dispatch(increase());
};
const minusNum = () => {
// 5
dispatch(decrease());
};
return (
<div className="container">
<h1>{`Count: ${1}`}</h1>
<div>
<button className="plusBtn" onClick={plusNum}>
+
</button>
<button className="minusBtn" onClick={minusNum}>
-
</button>
</div>
</div>
);
}
👇🏻 자세한 구현사항
1. react-reduxd에서 useDispatch를 불러온다
import { useDispatch } from 'react-redux';
2. Action creator 함수인 increase, decrease를 import한다.
import { increase, decrease } from './index.js';
3. useDispatch의 실행값을 변수에 저장해서 dispatch 함수를 사용
const dispatch = useDispatch();
4. dispatch를 통해 action 객체 를 Reducer함수로 전달한다.
const plusNum = () => {
dispatch(increase());
};
5.
const minusNum = () => {
dispatch(decrease());
};
2. useSelector
- 컴포넌트와 state를 연결하여 Redux의 state에 접근 할 수 있게 해주는 메서드
// 1
import { useDispatch, useSelector } from 'react-redux';
import { increase, decrease } from './index.js';
export default function App() {
const dispatch = useDispatch();
// 2
const state = useSelector((state) => state);
// 3
console.log(state);
const plusNum = () => {
dispatch(increase());
};
const minusNum = () => {
dispatch(decrease());
};
return (
<div className="container">
{/* 4 */}
<h1>{`Count: ${state}`}</h1>
<div>
<button className="plusBtn" onClick={plusNum}>
+
</button>
<button className="minusBtn" onClick={minusNum}>
-
</button>
</div>
</div>
);
}
👇🏻 자세한 구현사항
1. react-redux에서 useSelector를 불러온다.
import { useDispatch, useSelector } from 'react-redux';
2. useSelector의 콜백 함수의 인자에 Store에 저장된 모든 state가 담긴다.
const state = useSelector((state) => state);
3. console.log()로 Store에 저장된 기존 state값인 1을 확인 할 수 있다.
console.log(state);
4. Store에서 꺼낸 state를 화면에 나타나기 위해 변수 state를 사용한다.
<h1>{`Count: ${state}`}</h1>
5. +,- 버튼 누르면 state 변경확인 가능
Redux의 세가지 원칙
1. Single source of truth
Redux에는 데이터를 저장하는 Store라는 단 하나뿐인 공간에서 동일한 데이터를 들고와야한다.
2. State is read-only
Redux의 상태는 읽기전용으로 직접 변경할 수 없고 Action객체가 있어야만 상태를 변경할 수 있다.
3. Changes are made with pure functions
변경은 순수함수로만 이루어진다.
https://redux.js.org/tutorials/fundamentals/part-2-concepts-data-flow#core-concepts-and-principles
Flux 패턴
Flux는 리액트의 상태관리를 위한 패턴중 하나로, 단반향 데이터 흐름을 따른다. Flux패턴은 Dispatcher, Store,View로 구성되어있으며 View에서 Action을 발생시켜 Dispatcher로 전달하면, Dispatcher는 등록된 모든 Store에게 Action을 전달한다. Store에서는 전달받은 Action을 처리하여 내부 상태를 업데이트하고, View에게 변경된 상태를 전달한다.
리덕스는 Flux패턴을 발전시킨것으로 단일 스토어를 사용하며, 이스토어에 모든 어플리케이션 상태가 저장된다. 상태의 변경은 액션을 발생시키고 리듀서가 액션을 처리해서 이전 상태와 액션을 받아 새로운 상태를 반환한다.
SPA가 발전하면서 웹 어플리케이션의 복잡도가 증가하게 되어 기존에 사용하던 MVC나 MVVM패턴에 한계가 생겨 페이스북에서는 Flux 패턴을 개발하여 복잡한 UI컴포넌트를 보다 효율적으로 관리할 수 있게 되었다.
'React' 카테고리의 다른 글
[React] What is React? (2) | 2023.05.07 |
---|---|
[Redux] Redux toolkit (0) | 2023.04.25 |
[React] 쇼핑몰앱 장바구니기능을 구현해보자 (2) | 2023.04.21 |
[React]검색어 자동완성과 클릭투에디트를 구현해보자 (1) | 2023.04.20 |
리액트로 모달창,토글,탭,태그 구현 (0) | 2023.04.19 |