Redux

Rock Kyun·2023년 11월 9일
3
post-custom-banner

오늘의 학습

  • Redux

Redux란

  • 전역 state를 관리.

  • action이 일어나면 dispatch가 reducer에 action을 전달하여 state를 업데이트

     	  	     (action.type, payload) 전달
    1. action -------------------------------> dispatch
    		   
    	    	 (action.type, payload) 전달
    2. dispatch -----------------------------> reducer
    
    3. reducer : 설정해둔 switch문에서 action.type에 따라 state를 업데이트

필요한 배경지식

  • Ducks 패턴

Ducks 패턴이란

  • 리덕스를 사용하기 위해서는
    리덕스의 구성 요소 (config, module)를 먼저 설정하고 준비해야 하는데
    구성 요소인 module을 각각의 개발자가
    각각의 형태로 만들면 협업에 어려움이 생긴다.
    그렇기에 구성 요소를 준비할 때 패턴에 따라 준비하고
    협업 시 지장이 없도록 하기 위해 나온 패턴이다.

Ducks 패턴의 조건

  • Reducer 함수를 export default 한다.
  • Action creator 함수를 export 한다.
  • Action type은 app/reducer/ACTION_TYPE 으로 한다.
    (외부 라이브러리로서 사용될 경우 또는 외부 라이브러리가 필요로 할 경우에는 UPPER_SNAKE_CASE 로만 작성해도 괜찮다.)

Ducks 패턴을 왜 사용하는가

  • 하나의 state를 다루는 하나의 module에
    reducer, action type, action creator가 모두 존재하도록 하여
    나중에 혼란이 없도록 하는 것.

사용법

1. redux, react-redux 설치

  • npm 설치 명령어

    npm i redux react-redux

  • yarn 설치 명령어

    yarn add redux react-redux

2. 디렉토리 및 config, module 생성 (Ducks 패턴)

  • src 폴더에 config 폴더, module 폴더를 생성
  • config 폴더에 configStore.js 생성

configStore.js의 역할

  • Redux의 핵심
  • 모든 state를 담는 store를 소유.
  • 모든 state를 다루는 reducer를 하나로 합쳐서 소유.

configStore.js 예시

<configStore.js>

import {legacy_createStore as createStore} from 'redux';
import {combineReducer} from 'redux';

// 인자는 module 파일에서 만든 reducer가 들어감. ({key:value 형태로})
const rootReducer = combineReducer({});

// 모든 reducer 뭉탱이를 가진 store
const store = createStore(rootReducer);

export default store

import { legacy_createStore as createStore } 하는 이유

  • createStore로 import 해도 아무 문제 없다. (Redux가 공식적으로 발표)
    다만 그냥 createStore를 하면 이렇게 creatStore() 취소선이 있다.

3. index.js에 store 주입

  • index.js에서 store를 import 후 Provider로 감싸준다.
  • <Provider> 에 store를 전달한다.
<index.js>
  
import store from '/src/config/configStore'
import { Provider } from "react-redux";


const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>
);

4. module 만들기

  • module 폴더에 .js로 생성.
  • 초기값 설정
  • reducer함수 생성
  • export default 리듀서이름

counter 모듈 예시

<counter.js>

// 초기 상태값 (state 같은 것)
const initialState = {
  number: 0,
};

// counter 리듀서 (state 변경 함수 같은 것)
const counter = (state = initialState, action) => {
  switch (action.type) { // switch문을 통해 type에 따라 작동할 코드를 설정
    case "ADD_COUNT":
      return { number: state.number + 1 } // initialState의 값을 업데이트
    default:
      return state;
  }
};

// export default 한다.
export default counter;
  • configStore.js로 돌아가서 combieReducer의 인자로 추가하기 (key : value 형태로)
<configStore.js>

  // key와 value의 이름이 동일하면
  // 한 번만 적어도 됨 {counter: counter} -> {counter}
const rootReducer = combineReducer({counter}); 

5. 사용해보기!

  • 사용하고자 하는 컴포넌트에 가서
    useSelector()로 원하는 state를 가져온다.
  • useDispatch() state를 업데이트 하는 reducer에 타입 객체를 전달한다.

사용 예시

<CounterApp.jsx>
  
 const counter = useSelector((state) => state.counter); // state는 객체로 온다.
 const dispatch = useDispatch();

// 버튼을 눌렀을 때 counter state의 number를 1 증가하는 함수
const addCount = () => {
  dispatch({type:"ADD_COUNT"}}); // dispatch()로 type 객체 전달
}


<h1>{counter.number}</h1> // 0
<button onClick={addCount}>카운트 증가</button> // counter.number가 1씩 잘 증가한다.

느낀점

  • Context API와 달리 사전설정이 까다롭고
    눈과 손에 안 익어서 익숙해질 때까지는
    메모를 여러 번 들춰볼 거 같다.

    그리고 여기서 끝이 아니라
    Action type, Action creator 설명이 아직 남았다.
    이 두 가지는 human error를 줄이고
    유지 / 보수에 편리함을 위한 방법인데
    내일 적어봐야겠다..

post-custom-banner

0개의 댓글