망할 리덕스 이해하기

자몽·2021년 7월 8일
3

React

목록 보기
2/7
post-thumbnail

🟥 왜 리덕스를 사용하나요?

문제점

  1. 자바스크립트에서 관리해야 할 상태가 많아져 상태 관리의 어려움이 생기게 되었다.

    컴포넌트 수리덕스일반
    2개4개 상태관리4개 상태관리
    4개8개 상태관리16개 상태관리
    6개12개 상태관리36개 상태관리

    이처럼 리덕스를 사용하지 않으면 상태 관리를 할 때, 기하급수적으로 많은 상태를 관리해야 하는 문제가 생긴다.

  1. 쓸모없이 여러 컴포넌트를 통해 지나감

    위 사진의 첫번째 without Redux에서 보이는 것과 같이, 하나의 상태를 바꾸기 위해서는 여러 컴포넌트를 지나쳐야 했다.

🟩 REDUX

자바스크립트 어플리케이션에서 흔히 쓰이는 상태 컨테이너로, REDUX를 통해 상태 관리를 컴포넌트의 바깥에서 관리 할 수 있다.

REDUX 구성

REDUX의 흐름은 다음과 같다.
Component->Action->Reducer->Store

Component

화면에 보여지는 앱(view)

dispatch [Component-> Action] : 액션을 발생시킴


Action

상태변화를 일으키기 위해서 액션은 바뀔 부분을 지시하고 그런 변경에 필요한 데이터를 제공한다.

출처: https://12bme.tistory.com/493 [길은 가면, 뒤에 있다.]

handle [Action->Reducer] : action에 정의되어있는 내용이 reducer에 의해 핸들링됨


Reducer

이전 상태(state), Action을 받아서 변화를 일으킨다
update [Reducer->Store] : 핸들링에 따라서 상태값이 업데이트됨


Store

현재 상태, Reducer 등 상태에 관한 데이터를 store에 담는다.
subscribe [Store->Component] : 업데이트된 스토어를 subscriber를 통해 실시간으로 받아와서 사용

비유

어...이해가 안가요. (사실 저도 redux 공부하기 위해서 3일을 투자했다는..)
네 정상이에요. 그럼 한번 비유를 들어보겠습니다.

리덕스가 없는 세상은 택배가 존재하지 않는 세상이에요.
그래서 모든 일이 직거래로만 일어납니다.

리덕스가(택배 회사)가 존재한다면? 우리가 흔히 아는대로 택배를 주문할 때 다음과 같은 과정을 거칩니다.

Component

고객 그 자체


Action

원하는 물품을 선택해 주문한다.


Reducer

직원이 주문을 받고 물품을 가져와 포장한다.


Store

현재 고객의 정보물품은 모두 택배 회사의 서버에 저장되어있다.


여기까지가 제가 redux를 최대한 이해하기 쉽게 비유한 내용이며, 자세히 파고들면 약간은 달라질 수 있지만 우선 redux를 막 공부하는 입장에서는 '아 이런식으로 redux가 흘러가는구나.'라고 생각해 주세요.

🟦 실습:

실습의 목표는 다음과 같다.
웹페이지상에 Point 점수가 표시되고, 버튼을 통해 Point점수를 증가시킬 수 있다.

기본 세팅

yarn add ㅁㅁㅁ
npm install ㅁㅁㅁ
터미널에서 ㅁㅁㅁ 부분에 다음과 같은 라이브러리를 넣어 실행시켜주면 기본적인 redux 라이브러리를 다운받을 수 있다.

  1. 'react-redux'
  2. 'redux'

📕 App.js

import React from 'react';
import Point from './Point';

const App = () => {
  return (
      <div className="App">
        <Point />
      </div>
  )
}

export default App;

기본적인 App.js 를 만들었고, App 클래스 내부에는 Point클래스가 들어가있다.


📘 Point.js

import React from 'react';

const Point = () => {
    return (
        <div className="Point">
            <h2>점수: </h2>
            <button>point 획득</button>
        </div>
    )
}
export default Point;

Point 컴포넌트는 점수를 나타내는 <h2>태그와, 그러한 점수를 증가시켜주는 <button>이 존재한다.


action.js, reducer.js, store.js

REDUX에서 action, reducer, store는 필수적인 존재이다.

위와 같이, src폴더에 redux 폴더를 생성해주고, 내부에 action.js, reducer.js, store.js를 만들어놓는다.

자, 여기서부터 정신을 놓지 말고 집중해야 한다.(중요!!)


📕 action.js

원하는 물품을 선택해 주문하기

상태 변화(여기서는 Point 증가)를 일으키기 위해
Point.js 컴포넌트에서는 action를 실행하라고 dispatch(action 실행해주세요!)를 보낸다.


const ADD_POINT = 'ADD_POINT';

export const addPoint = () => {
    return {
        type: ADD_POINT
    }
}

Point 증가를 주기 위해, ADD_POINT를 type로 지정한다.

여기서 들었던 의문.

엥 왜 굳이 열심히 action.js 파일을 만들어놓고, 하는 일이 type 반환밖에 없어요?

이러한 이유는 바로 다음에 나오는 reducer.js에서 찾아볼 수 있다.(reducer는 action과 state을 받아 동작한다.)


📘 reducer.js

직원이 주문을 받고 물품을 가져와 포장하는 과정

상태에 어떠한 변화가 필요했을 때, action을 발생시켰다면,
reducer는 이러한 action현재의 상태를 받아, 변화를 일으킨다.

const ADD_POINT = 'ADD_POINT';

const init = {
    count: 7
}
const pointReducer = (state = init, action) => {
    switch (action.type) {
        case ADD_POINT:
            return {
                ...state,
                count: state.count + 1
            }
        default: return state;
    }
}
export default pointReducer;

여기서 pointReducer는 (현재의 상태, 액션)와 같이 2가지의 파라미터를 받으며,
현재의 상태가 없을 경우를 대비해, init과 같은 기본적 상태를 미리 정의해 두었다.

reducer는 앞서 action에서 만들었던 type을 기반으로 하여 switch문을 통해 원하는 타입(여기서는 ADD_POINT를 통해 포인트 증가가 목적이므로 ADD_POINT)을 선택한다.

...state를 사용하는 이유는?
Reducer는 전체 state를 하나로 반환해야하기 때문에
...state로 현재 이 액션과 상관없는 state값들을 보존시켜줘야한다.


📗 store.js

고객의 정보와 물품은 모두 택배 회사에 저장됨

자 이제 거의 마지막 단계이다.
우리가 힘들게 actionreducer를 통해 상태를 변화시켰다면, 이러한 상태에 관한 데이터를 store에 담아주어야 한다.

import { createStore } from "redux";
import pointReducer from "./reducer";

const store = createStore(pointReducer);

export default store;

redux 라이브러리에는 createStore가 기본적으로 존재하는데, 이를 사용해 우리가 만들었던 redux를 파라미터로써 넣어준다.

마무리

마무리라 이름이였지만 사실 조금의 과정이 더 남아있다.

📕 App.js

//import React from 'react';
import { Provider } from 'react-redux';

import Point from './Point'; 
import store from './redux/store'; 
 
//const App = () => {
//  return (
    <Provider store={store}> 
//      <div className="App">
//        <Point />
//      </div>
    </Provider> /* store와의 연동을 위해 Provdier 추가 */
//  )
//}

//export default App

앞서 App.js와 달라진 부분은 주석가 되지 않은 부분이다.
store와 컴포넌트의 연동을 위해서 Provider를 사용한다.

Provier: react-redux 라이브러리에 내장되어있는, 리액트 앱에 store 를 손쉽게 연동 할 수 있도록 도와주는 컴포넌트입니다.

📘 Point.js

//import React from 'react';
import { connect } from 'react-redux';
import { addPoint } from './redux/action';

const Point = (props) => {
//    return (
//        <div className="Point">
            <h2>점수: {props.count}</h2>
            <button onClick={() => props.addPoint()}>point 획득</button>
//        </div>
//    )
//}

const mapStateToProps = (state) => {
    return {
        count: state.count
    }
}
const mapDispatchToProps = {
    addPoint
}

export default connect(mapStateToProps, mapDispatchToProps)(Point);

점수를 변화해주기 위해서 props를 통해 count를 가져왔다.
또한 onClick이벤트 함수에서는 addPoint action을 props로 받아서 사용하였다.

mapStateToProps: 컴포넌트에 props로 넣어줄 리덕스 스토어 상태에 관련된 함수
mapDispatchToProps: 컴포넌트에 props로 넣어줄 액션을 디스패치하는 함수들에 관련된 함수

Point 컴포넌트의 props.countmapStateToProps를 통해 store에서 count 상태를 가져오게 되고,
props.addPoint()mapDispatchToProps를 통해 store에 접근한 컴포넌트가 dispatch를 사용할수 있게 만들어준다.

🟪 마치며..

혹시라도 위에서 실습할 때 사용한 코드가 필요하다면 제 github에 오셔서 확인할 수 있습니다.
링크: https://github.com/OseungKwon/practice-react/tree/main/REDUX%20이해하기

여기까지가 3일동안 열심히 공부한 redux를 정리한 내용이며, 이제 막 redux를 배운 단계이기에 일부 비유나 개념에 약간의 오류가 있을 수도 있습니다.
혹시 잘못된 부분이 있으면 언제든지 알려주시기 바랍니다.!

참고 :
https://www.youtube.com/watch?v=wSbjROmXTaY&list=PLpJDjPqxGWGoqwd8JkvC_V0zPjJRmbRsI&index=2 code Scalper님 유튜브 일부분 참고

profile
꾸준하게 공부하기

0개의 댓글