Redux

Redux

Redux란, 자바스크립트 애플리케이션의 전역 상태를 효율적으로 관리 할 수 있게 도와주는 라이브러리이다.
복잡한 상태 관리가 이루어지는 SPA에서 특히 유용하게 사용된다. Redux는 리액트가 뿐만 아니라 순수 Javascript에서도 사용 할 수 있다.

리액트 상태 관리에 대한 설명

예를 들어 다음과 같은 구조의 컴포넌트들이 있다고 보자.
Pasted image 20231109094219.png

RootComponent에서 F까지 값을 전달해주기 위해서는 ROOT → B → E → F 와 같은 경로를 따라야한다.

리덕스를 쓰게 된다면 Props Drilling 없이 state의 변화를 리덕스 스토어를 이용하여 감지 하게 된다. 즉, 전역 state를 리덕스 스토어를 통해 관리할 수 있게 된다.

Pasted image 20231109094528.png
ROOT → 리덕스 스토어 → F
즉, 리덕스는 하나의 전역 상태를 관리하는 중앙화 저장소와, 특정한 패턴을 사용하여 전역 state를 쉽게 관리할 수 있도록 도와주는 상태 관리 라이브러리이다.

리덕스를 사용한 data의 flow를 그림으로 나타내면 다음과 같다.
https://redux.js.org/assets/images/ReduxDataFlowDiagram-49fa8c3968371d9ef6f2a1486bd40a26.gif

리덕스 사용법

리덕스를 사용하기 위해 우선 다음과 같이 프로젝트 구조를 만든다.

📂 src
📂 redux
📂 config
📄 configStore.js
📂 modules
📄 counter.js
📄 users.js
...

Store

Redux의 state를 저장하는 단 하나의 공간을 store라고 한다. store는 createStore, configureStore 함수에 생성한 root reducer를 인자로 넘겨 생성한다.

import { configureStore } from '@reduxjs/toolkit'
// import { createStore } from "redux";

export default const store = configureStore({ reducer: counterReducer })

// const legacyStore = createStore(counterReducer);

생성한 store를 적용하기 위해서는 root 컴포넌트에서 Provider로 감싸주고, store 속성에 생성한 store를 담아준다.

const root = ReactDOM.createRoot(document.getElementById('root'));  
root.render(  
  <Provider store={store}>  
    <App />  
  </Provider>  
);
하나의 어플리케이션, 하나의 스토어

하나의 애플리케이션 에서는 단 한개의 스토어를 만들어서 사용한다. 여러개의 스토어를 사용하는게 가능하기는 하나, 권장 되지는 않는다.

Action

action은 typepayload 속성을 포함한 자바스크립트 객체이다.

const PLUS_ONE = "counter/PLUS_ONE"

const addTodoAction = {
  type: PLUS_ONE,
  payload: 'Buy milk'
}

action 객체는 type 속성을 필수적으로 가지고 있어야 하고, 그 외의 값들은 개발자가 마음대로 넣어 줄 수 있다.

Action Creator

const PLUS_N = "counter/PLUS_N"

export const plusN = (payload) => {  
  return {  
    type: PLUS_N,  
    payload: payload  
  }  
}

action creator는 handler라고도 불리며, action 객체를 리턴하는 함수를 말한다. 단순히 파라미터를 받아와서 액션 객체 형태로 만들어 준다.

Reducer

리듀서는 stateaction을 인수로 받고, 하나의 state로 반환하는 함수이다.

"Reducer" functions get their name because they're similar to the kind of callback function you pass to the Array.reduce() method.

// reducer: 'state에 변화를 일으키는' 함수  
// input: state와 action  
const counter = (state = initialState, action) => {  
  switch (action.type) {  
    case PLUS_ONE:  
      return {...state, number: state.number + 1};  
    case MINUS_ONE:  
      return {...state, number: state.number - 1};  
    case PLUS_N:  
      return {...state, number: state.number + action.payload}; 
    case MINUS_N:  
      return {...state, number: state.number - action.payload}; 
    default:  
      return state;  
  }  
}

Selectors

selector는 store에 저장된 state중 특정한 value를 가져올 때 사용하는 함수이다. useSelector라는 Hook을 이용하여 데이터를 가져올 수 있다.

const counter = useSelector((state) => state.counter);

selector를 사용한 컴포넌트는 자동으로 store의 변화를 구독하게되며, 값이 변할 경우 컴포넌트가 리렌더링 된다.

Dispatch

dispatchstate를 업데이트할 수 있는 유일한 방법이다. useDispatch Hook을 이용하여 액션을 발생시킨다!

const [number, setNumber] = useState(0);

// store에 접근하여 counter 값을 읽어오자  
const counter = useSelector(state => {  
  return state.counter;  
});

const dispatch = useDispatch();  
  
const handlePlus = () => {  
  dispatch(plusN(number))  
}  
  
const handleMinus = () => {  
  dispatch(minusN(number))  
}  
  
return (  
  <div className="App">  
    <button onClick={handlePlus}>+</button>  
    <button onClick={handleMinus}>-</button>  
  </div>  
);