리액트를 다루는 기술 - 16장

velbie·2020년 11월 6일
0
post-thumbnail

액션, 액션생성함수, 리듀서, 스토어, 디스패치, 구독 이런게 있습니다.
프로젝트를 만들면서 배워보겠습니다.

리덕스 프로젝트 만들기

yarn global add parcel-bundler
mkdir banilla-redux
cd vanilla-redux
yarn init -y
<!-- index.html -->
<html>
    <head>
        <link rel="stylesheet" type="text/css" href="index.css" />
    </head>
    <body>
        <div class="toggle"></div>
        <hr />
        <h1>0</h1>
        
        <button id="increase">+1</button>
        <button id="decrease">-1</button>
        <script src="./index.js"></script>
    </body>
</html>
// index.js
const divToggle = documnet.querySelector(".toggle");
const counter = documnet.querySelector(".hi");
const btnIncrease = documnet.querySelector("#increase");
const btnDecrease = documnet.querySelector("#decrease");

한번 실행해보고 redux를 다운받습니다.

pacel index.html
yarn add redux

간단한 UI를 구성해 보겠습니다.

// index.css

.toggle {
  border: 2px solid black;
  width: 64px;
  height: 64px;
  border-radius: 32px;
  box-sizing: border-box;
}

.toggle.active {
  background: yellow;
}

index.html 변경했습니다. (원이생겼습니다.)
리덕스 공부할 준비가 끝났습니다.

액션타입과 액션생성함수 정의

프로젝트의 상태에 변화를 일으키는 것을 액션이라고 합니다.
(액션은 객체로 표현됩니다.)
액션이름은 대문자로 해야합니다.

// index.js
const divToggle = documnet.querySelector(".toggle");
const counter = documnet.querySelector(".hi");
const btnIncrease = documnet.querySelector("#increase");
const btnDecrease = documnet.querySelector("#decrease");

// 액션이름을 추가
const TOGGLE_SWITCH = "TOGGLE_SWITCH";
const INCREASE = "INCREASE";
const DECREASE = "DECREASE";

// 액션 생성 함수 추가
const toggleSwitch = () => ({ type: TOGGLE_SWITCH });
const increase = (difference) => ({ type: INCREASE, difference });
const decrease = () => ({ type: DECREASE });

이 액션 이름을 사용하여 액션 객체를 생성하는 액션 생성 함수를 작성해 줍니다.
index.js에서 초기상태를 만들어줍니다.

const initialState = {
  toggle: false,
  counter: 0,
};

리듀서 함수 정의

리듀서는 변화를 일으키는 함수 입니다.
함수의 파라미터로는 state와 action 값을 받아옵니다

// index.js initialState 밑에 작성

// state가 undefined 일 때는 initialState를 기본값을 사용
function reducer(state = initialState, action) {
  // action.type에 따라 다른 작업을 처리함
  switch (action.type) {
    case TOGGLE_SWITCH:
      return {
        ...state, // 불변성 융지
        toggle: !state.toggle,
      };
    case INCREASE:
      return {
        ...state, // 불변성 융지
        counter: state.counter + action.difference, // 이건 뭐지?
      };
    case DECREASE:
      return {
        ...state,
        counter: state.counter - 1,
      };
    default:
      return false;
  }

스토어 만들기

스토어에 리듀서를 넣어줍니다.

// index.js
import { createStore } from "redux";

(...)

const store = createStore(reducer);

render 함수 만들기

render 함수를 작성해보겠습니다. 이 함수는 상태가 업데이트 될 때마다 호출되며, 리액트의 render 함수와는 다르게 UI의 상태에 따라 변경해줍니다.
스토어 밑에다가 아래 코드를 추가합니다.

//index.js 

const render = () => {
  const state = store.getState(); // 현재 상태를 불러옵니다
  // 토글 처리
  if (state.toggle) {
    divToggle.classList.add("active");
  } else {
    divToggle.classList.remove("active");
  }
  // 카운터 처리
  counter.innerText = state.counter;
};

render();

렌더함수는 현재 상태를 불러와 화면막 변경해줍니다.
아직 현재상태를 변경안해줬으니 클릭했을 때 값이 올라가진 않습니다.

구독하기

스토어의 상태가 바뀔때마다 render 함수가 호출되도록 해줄것입니다.
스토어의 내장 함수 subscribe를 사용하여 수행할수 있습니다.

아 그냥 그래서 최종 코드가 아래에 있음


import { createStore } from "redux";
const divToggle = document.querySelector(".toggle");
const counter = document.querySelector("h1");
const btnIncrease = document.querySelector("#increase");
const btnDecrease = document.querySelector("#decrease");

// 액션이름을 추가
const TOGGLE_SWITCH = "TOGGLE_SWITCH";
const INCREASE = "INCREASE";
const DECREASE = "DECREASE";

// 액션을 만듦
const toggleSwitch = () => ({ type: TOGGLE_SWITCH });
const increase = (difference) => ({ type: INCREASE, difference });
const decrease = () => ({ type: DECREASE });

// 초기상태
const initialState = {
  toggle: false,
  counter: 0,
};

// state가 undefined 일 때는 initialState를 기본값을 사용
function reducer(state = initialState, action) {
  console.log(action);
  // action.type에 따라 다른 작업을 처리함
  switch (action.type) {
    case TOGGLE_SWITCH:
      return {
        ...state, // 불변성 융지
        toggle: !state.toggle,
      };
    case INCREASE:
      console.log("일로 안들어오나?");
      return {
        ...state, // 불변성 융지
        counter: state.counter + action.difference, // 이건 뭐지?
      };
    case DECREASE:
      return {
        ...state,
        counter: state.counter - 1,
      };
    default:
      return state;
  }
}

const store = createStore(reducer);

const render = () => {
  const state = store.getState(); // 현재 상태를 불러옵니다
  // 토글 처리
  if (state.toggle) {
    divToggle.classList.add("active");
  } else {
    divToggle.classList.remove("active");
  }
  // 카운터 처리
  counter.innerText = state.counter;
};

render();
store.subscribe(render);

divToggle.onclick = () => {
  store.dispatch(toggleSwitch());
};
btnIncrease.onclick = () => {
  store.dispatch(increase(1));
};
btnDecrease.onclick = () => {
  store.dispatch(decrease());
};

리덕스를 사용하니깐 간단한 어플도 복잡해졌다. 하..

정리를 해보자면

리듀서는 변화를 일으키는 함수입니다.

리듀서는 스토어 안에 넣어놓고
액션과 상태를 리듀서에 전달하기 위해 스토어에 넣어줍니다.(dispatch)

그럴려면 초기상태, 액션을 발생시키는 함수 가 필요합니다.

그냥 이렇게 상태를 관리하나 봅니다.. 휴

profile
안녕하세요

2개의 댓글

comment-user-thumbnail
2021년 9월 5일

onClick 이벤트가 발생을 안하는것 같아요ㅠ
또한 콘솔에 이런 에러도 떠요 Uncaught TypeError: Cannot set property 'innerText' of nullㅠ

1개의 답글