
자바스크립트 앱을 위한 예측 가능한 상태 컨테이너
시간여행형 디버거와 결합된 실시간 코드 수정 개발자 경험 제공
Redux를 다른 뷰 라이브러리나 리액트와 함께 사용 가능
상태 관리 라이브러리
리액트에서 클릭 이벤트 발생 -> Hook을 사용 (useState) 리액트에게 값의 변경을 알림
Redux 앱을 만들기에 필수적인 패키지와 함수들을 포함하여 작업을 단순화한다.
리덕스도 useState와 마찬가지로 변하는 값을 관리해주는 관리 시스템
전역으로 데이터 상태를 관리
중앙 데이터를 갖는다. (Store) - 데이터는 상태(state)state를 수정하는 reducer 함수를 만듦dispatch를 이용하여 reducer에게 state 값 수정하라고 요청함 (dispatch action)reducer이 state 값을 수정하면 subscribe를 사용하여 수정된 부분을 UI에 업로드
store에 저장하고 싶은 상태를 저장하나의 store에 저장에러가 발생한다면 store만 관리하면 됨reduceraction과 이전 state값으로 어떻게 값을 처리할지 결정renderconst state = store.getState()를 통해 데이터를 받아야 한다.subscribeaction, dispatchaction 객체는 type 필드를 반드시 가지고 있어야 한다. (이전 state 값을 참고하여 새로운 state 값 생성)useContext : 리액트의 prop-drilling를 피하기 위해 사용하지만 프로젝트가 커지면서 Provider를 많이 사용하게 된다면 복잡해진다.
Redux는 뷰 / 바닐라 JS에서든 사용이 가능하며 state관리의 엄격함과 1개의 저장소, 업데이트 기능 등을 제공하여 큰 프로젝트 상태 관리에 적합하다.
변경되는 값을 사용하는 컴포넌트만 리렌더링할 수 있도록 최적화해줌
const rootReducer = combineReducers({
aReducer,
bReducer,
cReducer,
})
상태 저장 store는 1개만 사용 (객체 구조로 저장하여 사용)
reducer 함수는 순수 함수로만 만들어야 함 (이전 상태와 액션 파라미터에만 의존)
import {createStore} from 'react';
const plus = document.getElementById("plus");
const minus = document.getElementById("minus");
const number = document.getElementById("number"); // 수량
const quantity = document.getElementById("quantity"); // 페이지 하단에 총 수량
const totalPrice = document.getElementById("total"); // 페이지 하단에 총 가격
const PRICE = 17500;
// 2. state값 수정하는 reducer 함수 (state, action을 전달)
const countReducer = (state = 0, action) => {
switch (action.type) {
case 'ADD':
minus.disabled = false;
return state + 1;
case 'SUBSTRACT':
plus.disabled = false;
retrun state - 1;
default:
return state;
}
}
// 1. store 생성
const store = createStore(countReducer);
// 3. dispatch를 사용하여 reducer에게 action을 넘기기
const addNumber = () => {
store.dispatch({type:'ADD'});
}
const substractNumber = () => {
store.dispatch({type:'SUBSTRACT'});
}
plus.addEventListener('click', addNumber);
minus.addEventListener('click', substractNumber);
// 4. subscribe를 활용하여 state 상태 변화를 감지하여 ui 업데이트하는 함수 생성
const handleWrite = () => {
number.innerText = store.getState();
quantity.innerText = store.getState();
totalPrice.innerText = store.getState() * PRICE;
console.log(store.getState());
}
// update UI
store.subscribe(handleWrite);
npx create-react-app my-app --template basic-react
npm i redux react-redux
리듀서1 : 상품 구매 개수 관리
리듀서2 : 재고 없는 경우 나오는 메시지 관리
goodsCounter.jsx
// 액션 생성 함수
export const addNumber = () => {
return {type : 'ADD'}
}
export const substractNumber = () => {
return {type : 'SUBSTRACT'}
}
// 초기값 설정
const initialState = {
stock : 100,
goods: 1
}
// 상품 구매 개수 관리하는 리듀서
const goodsReducer = (state = initialState, action) => {
switch(action.type) {
case "ADD":
return {
...state,
stock : state.stock - 1,
goods : state.goods + 1,
}
case "SUBSTRACT":
return {
...state,
stock : state.stock + 1,
goods : state.goods - 1,
}
default:
return state
}
}
}
export default goodsReducer;
import {combineReducers} from 'redux';
import goodsReducer from './goodsCounter';
import stockReducer from './stockCounter';
const rootReducer = combineReducers({
goodsReducer,
stockReducer
})
export default rootReducer;
import React from 'react'
import {creatRoot} from 'react-dom/client';
import App from './App';
import { createStore } from 'redux';
import rootReducer from './modules';
import { Provider } from 'react-redux';
const store = createStore(rootReducer);
console.log(store.getState());
const container = document.getElementById('root');
const root = createRoot(container);
root.render(
<Provider store={store}>
<App tab="home" />
</Provider>,
);
import { useSelector, useDispatch } from 'react-redux'
import { addNumber, substractNumber } from '../modules/goodsCounter'
function GoodCounter() {
// store 상태 조회 : useSelector
const {stock, goods} = useSelector(state => ({
stock: state.goodsReducer.stock,
goods: state.goodsReducer.goods,
}))
console.log(stock, goods);
// store의 dispatch를 함수 내부에서 사용가능하도록 useDispatch
const dispatch = useDispatch()
const onAddNumber = () => dispatch(addNumber())
const onSubstractNumber = () => dispatch(substractNumber());
return (// 작성)
}
export default GoodCounter
리덕스 공식 팀에서 만든 툴로 리덕스와 관련된 틀이 묶여있다.
npm install @reduxjs/toolkit react-redux
액션 생성 함수 필요 X
...state 없어짐
swith / if 문 대신 함수 형태로 변경
modules/goodsCounter.jsx
import {createSlice} from '@reduxjs/toolkit';
const initialState = {
stock: 10,
goods: 1
}
export const counterSlice = createSlice({
name : 'counter',
initialState,
reducers: {
// 함수로 변경됨
increment: (state) => {
// ...state 삭제
state.stock -= 1
state.goods += 1
},
decrement: (state) => {
state.stock += 1
state.goods -= 1
},
},
})
console.log(counterSlice)
export const {increment, decrement} = counterSlice.actoins;
export default counterSlice.reducer