자바스크립트 앱을 위한 예측 가능한 상태 컨테이너
시간여행형 디버거와 결합된 실시간 코드 수정
개발자 경험 제공
Redux를 다른 뷰 라이브러리나 리액트와 함께 사용 가능
상태 관리 라이브러리
리액트에서 클릭 이벤트 발생 -> Hook을 사용 (useState) 리액트에게 값의 변경을 알림
Redux 앱을 만들기에 필수적인 패키지와 함수들을 포함하여 작업을 단순화한다.
리덕스도 useState와 마찬가지
로 변하는 값을 관리해주는 관리 시스템
전역으로 데이터 상태를 관리
중앙 데이터
를 갖는다. (Store) - 데이터는 상태(state)state를 수정
하는 reducer 함수
를 만듦dispatch
를 이용하여 reducer에게 state 값 수정하라고 요청
함 (dispatch action)reducer이 state 값을 수정
하면 subscribe
를 사용하여 수정된 부분을 UI에 업로드
store
에 저장하고 싶은 상태를 저장하나의 store에 저장
에러가 발생
한다면 store만 관리하면 됨reducer
action
과 이전 state값
으로 어떻게 값을 처리할지 결정render
const state = store.getState()
를 통해 데이터를 받아야 한다.subscribe
action
, dispatch
action 객체
는 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