개발 노트

JavaScript Library - Redux 본문

JavaScript

JavaScript Library - Redux

알 수 없는 사용자 2022. 11. 15. 13:01

리덕스란?

JavaScript를 관리해주는 상태관리 라이브러리이고 본질은 Node.js 모듈이다.

 

상태관리?

State를 컴포넌트 안에서 관리하는 것.

 

왜 관리해야 하는가?

자식 컴포넌트들 간의 직접 전달은 불가능하다.

그래서 부모 컴포넌트를 통해서 주고 받아야 하는데 자식이 많아진다면 상태 관리가 매우 복잡해진다.

└state를 맨 아래 계층의 컴포넌트에서 사용하고자 할때 모든 계층을 지나며 props를 불필요하게 전달하게 된다

(버킷 릴레이 방식) => prop drilling(프로퍼티 내려꽂기)문제를 야기한다.

 = 전달 과정이 10개 이상 많은 과정을 거치게 된다면? 해당 prop을 추적하기 힘들어지기에 유지 보수가 더욱 어려워진다.

 

그렇기에 전역 상태 관리(global state management)를 해야하는데 상태관리의 복잡성을 해결해주는 라이브러리를 활용 할 수 있다.

상태 관리 툴이 해결해주는 문제

  • 전역 상태 저장소 제공
  • props drilling 이슈 해결

툴 종류 = React Context, Redux, Mobx

 

Redux의 기본 개념 : 세가지 원칙

  • Single source of truth
    -동일한 데이터는 항상 같은 곳에서 가져온다.
    즉, 스토어라는 하나뿐인 데이터 공간이 있다는 의미이다.
  • State is read-only
    리액트에서는 setState 메소드를 활용해야만 상태 변경이 가능하다.
    리덕스에서도 Action이라는 객체를 통해서만 상태를 변경할 수 있다.
  • Changes are made with pure functions
    변경은 순수함수로만 가능하다.
    리듀서와 연관되는 개념이다.

 

Store

store는 상태가 관리되는 오직 하나의 공간이다.

컴포넌트와는 별개로 스토어라는 공간이 있어서 그 스토어 안에 앱에서 필요한상태를 담는다.

 

Action

Action은 앱에서 스토어에 운반할 데이터(주문서)

Action은 자바스크립트 객체형식으로 되어있다.

 

Reducer

Action을 스토어에 바로 전달하는게 아니다.

액션을 리듀서에 전달하고 리듀서가 주문을 보고 스토어의 상태를 업데이트 하는 것이다.

즉 State에 변화를 일으키는 함수이고 parameter를 두개 받는다.

첫 번째는 현재 state(초기값), 두 번째는 액션 객체를 받는다.

액션을 리듀서에게 전달하기 위해서는 dispatch()메소드를 이용한다.

Action 객체 -> dispatch() -> Reducer 호출 -> 새로운 Store 생성.

Redux에서 위 개념을 구현하는 두 가지 방법

  • mapStateToProps()
  • Redux hooks = useSelector, useDispatch
    1. useDispatch 는 리덕스 스토어의 dispatch를 함수에서 사용할 수 있게 해주는 react-redux에서 제공하는 hook이다. 이것을 이용하여 각각의 액션들을 dispatch 해준다.
    2. useSelector는 리덕스 스토어의 state를 조회하는 hook이다.

Redux의 장점

1. 상태를 예측 가능하게 만든다.(순수함수를 사용하기 때문)

     └순수함수 = 부수효과가 없는 함수 즉, 어떤 함수에 동일한 인자를 주었을 때 항상 같은 값을 리턴.

function add(a,b){
    return a + b;
}

위의 함수는 값이 변경되지 않는 함수이기에 순수함수이다.

var c = 10;
function add2(a,b){
    return a + b + c;
}

 

위의 함수는 외부의 c라는 변수 값이 변하면 결과값이 달라지기에 순수함수가 아니다.

 

2. 유지보수(복잡한 상태 관리와 비교)

3. 디버깅에 유리(action과 state log 기록 시에) -> redux dev tool(크롬 확장)

4. 테스트를 붙이기에 용의(순수함수를 사용하기 때문)

 

아래는 타 블로그를 보고 따라한 예제이다.

출처 : https://ivorycode.tistory.com/entry/Redux%EC%9D%98-%ED%9D%90%EB%A6%84%EA%B3%BC-%EC%98%88%EC%A0%9C

src/store/modules/counter.js

const { createStore } = require("redux");  리덕스 모듈 생성


const INCREMENT = "INCREMENT";  ----action
const DECREMENT = "DECREMENT";

export const increment = () => {
  return {
    type: INCREMENT,              	
  };								
};									
									
export const decrement = () => {
  return {
    type: DECREMENT,
  };
};                                ----

const initialState = {            ----reducer
  number: 0,
};		

export default function counter(state = initialState, action) {
  switch (action.type) {				
    case INCREMENT:						   
      return {							
        number: state.number + 1,			
      };									
    case DECREMENT:							
      return {
        number: state.number - 1,
      };
    default:
      return state;
  }
}								   -----

1.action type, action creator 생성
-카운터에 필요한 2가지 액션을 만들어준다.

-다음은 액션 생성함수를 만들어 주면 되는데,
생성함수는나중에 컴포넌트에서 사용될 함수이므로  export키워드를  반드시 붙여준다.

 

2.reducer 생성

- 카운터에 적용될 초기값을 설정해준다. 보통 initialState라고 선언한다.
- 리듀서를 만들어준다. 그리고 switch문으로 액션이 발생했을 때의 값을 리턴하도록 작성한다.
   어떠한 액션도 발생하지 않았을 때는 default를 반환

 

src/store/module/index.js

import { combineReducers, CombineReducers } from "redux";
import counter from "./counter";

//import한 리듀서 이름을 그대로 사용하는 경우
export default combineReducers({
  counter,
});

//리듀서 이름을 지정하는 경우
// export default combineReducers({
//리듀서 이름 : import한 리듀서
//counterData : counter,
// });

3. combineReducer 생성

1. combineReducers와 위에서 export했던 counter 리듀서를 import 해준다.

2. 리듀서를 합쳐주는 방법은 리듀서 이름을 그대로 사용하는 경우, 직접 지정하는 경우 이렇게 2가지가 있다.

 

src/components/Counter.js

import { useDispatch, useSelector } from "react-redux";
import { decrement, increment } from "../store/modules/counter";

export default function Counter() {
  const dispatch = useDispatch();

  // import한 리듀서 이름을 그대로 사용하는 경우
  const count = useSelector((state) => state.counter.number);

  // 리듀서 이름을 지정하는 경우
  // const count = useSelector((state) => state.copunterData.number)

  return (
    <div>
      <h1>COUNTER</h1>
      <h4>{count}</h4>
      <br />
      <button onClick={() => dispatch(increment())}>+</button>
      <button onClick={() => dispatch(decrement())}>-</button>
    </div>
  );
}

4.Counter Component 생성

-1,2,3 과정을 통해 Redux 파일 구조를 생성했고, 파일을 활용할 곳인 컴포넌트를 만들어

View화면을 만들어주도록 하자.

 

src/App.js

import "./App.css";
import Counter from "./components/Counter";

function App() {
  return (
    <div className="App">
      <div className="App-header">
        <p>Study Redux</p>
        <Counter />
      </div>
    </div>
  );
}

5. Component 연결

-App.js 파일에 카운터 컴포넌트를 import 해준다.

 

src/index.js

import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import { createStore } from "redux";
import { Provider } from "react-redux";
import rootReducer from "./store/modules";

const store = createStore(rootReducer);

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById("root")
);

6. Store 생성

-하나의 애플리케이션엔 하나의 스토어가 존재한다.

스토어 안에는 state를 담고 있고, 업데이트될 때마다 다시 실행하게 한다.

- createStore를 생성하여 위의 과정에서 만든 리듀서를 parameter에 넣어준다. 만들어둔 combineReducer가 있으니 그것을 활용해보자.

- Provider는 react-redux에서 제공하는 컴포넌트로 리액트 프로젝트에 store를 쉽게 연동할 수 있도록 하는 컴포넌트다. Provider를 불러온 후, props에 아까 선언했던 store를 넣어주자.

 

 

 

 

'JavaScript' 카테고리의 다른 글

Js - trim()  (0) 2022.11.30
Javascript Library - Zustand  (0) 2022.11.15
Javascript - LocalStorage  (0) 2022.11.11
자바스크립트 fetch,callback,promise,async 게시글  (0) 2022.01.10
카카오 책검색 api 사용하기  (0) 2022.01.08