React - Redux(2)

최재홍·2023년 4월 19일
0

리덕스의 흐름을 도식화하면 다음과 같다.

  1. View 에서 액션이 일어난다.

  2. dispatch 에서 action이 일어나게 된다.

  3. action에 의한 reducer 함수가 실행되기 전에 middleware가 작동한다.

  4. middleware 에서 명령내린 일을 수행하고 난뒤, reducer 함수를 실행한다. (3, 4번은 아직 몰라도 됩니다!)

  5. reducer 의 실행결과 store에 새로운 값을 저장한다.

  6. store의 state에 subscribe 하고 있던 UI에 변경된 값을 준다.


useState에서는 이 과정이 어떻게 진행되었는가

// 예시 코드

// local state
const [number, setNumber] = useState(0)


// click handler
const onClickHandler = () => {
	setNumber(number + 1)
}

Redux에서는 이 과정을 어떻게 진행시켜야 하는가

  1. 리듀서에게 보낼 number를 +1하라는 '명령'을 만든다.
  2. 명령을 보낸다.
  3. 리듀서에서 명령을 받아 number+1을 한다.

더 세분화할 수 있지만 가장 간략하게 표현하면 상기와 같다.

1. 리듀서에게 보낼 '명령' 만들기

리듀서에게 명령을 보내기 위해서는 먼저 '명령'을 만들어야 한다. 리덕스에서는 명령을 'Action'이라고 한다. Action은 반드시 객체로 만들어서 전달되어야 한다. 그래서 이것을 액션 객체라고 부른다.

액션 객체는 반드시 type이라는 key를 가져야 한다. 그러면 리듀서는 type의 value를 분석한다.

// 예시 코드
//number에 +1 을 하는 액션 객체

{ type : "PLUS_ONE" };

type이라는 key의 value가 "PLUS_ONE"이라는 액션객체를 상정한 것.


2. 리듀서에게 "명령"(액션 객체) 보내기

앞으로는 "명령"을 "액션 객체"라고 표현하자.

액션 객체를 리듀서로 보내기 위해서는 새로운 Hook을 사용해야 한다. 그 훅은 useDispatch라는 훅이다. react-redux에서 import해서 사용할 수 있으며, 우리가 만든 액션 객체를 리듀서로 보내주는 역할을 하는 훅이다.

useDispatch라는 훅을 사용하기 위해서는 컴포넌트 안에서 아래와 같이 먼저 코드를 작성해서 dispatch라는 변수를 생성해줘야 한다. 이렇게 생성한 dispatch는 함수라는 점을 기억하자. 그래서 우리는 dispatch를 사용할 때 ()를 붙여서 함수를 실행하게 된다.

// src/App.js


import React from "react";
import { useDispatch } from "react-redux"; // import 해주세요.

const App = () => {
  const dispatch = useDispatch(); // dispatch 생성
  return (
    <div>
      <button>+ 1</button> {/* 버튼을 하나 추가해주세요. */}
    </div>
  );
};

export default App;

이렇게 선언된 dispatch를 실행하면서 매개변수로 액션객체를 넣어주면 된다. 만약 특정 버튼을 클릭했을 때 리듀서로 액션객체를 보내고 싶다면 아래와 같이 코드를 작성한다.

// src/App.js

import React from "react";
import { useDispatch } from "react-redux"; // import 해주세요.

const App = () => {
  const dispatch = useDispatch(); // dispatch 생성
  return (
    <div>
      <button
				// 이벤트 핸들러 추가
        onClick={() => {
					// 마우스를 클릭했을 때 dispatch가 실행되고, ()안에 있는 액션객체가 리듀서로 전달된다.
          dispatch({ type: "PLUS_ONE" }); 
        }}
      >
				+ 1
      </button>
    </div>
  );
};

export default App;

3. 액션객체의 type에 따라서 리듀서가 state값을 변경하는 코드 구현하기

이제 모듈 폴더로 돌아와 리듀서로 보낸 액션객체를 활용하여 state값을 변경하는 코드를 구현해보자.
모듈 폴더의 counter.js파일로 넘어와서 state에 있는 initialState를 변경해야 한다. 그러기 위해서는

  1. 컴포넌트로부터 dispatch를 통해 액션객체를 전달 받는다.
  2. action 안에 있는 type을 스위치문을 통해 하나씩 검사해서, 일치하는 case를 찾는다.
  3. type과 case가 일치하는 경우에, 해당 코드가 실행되고 새로운 state를 반환한다.
  4. 리듀서가 새로운 state를 반환하면, 그게 새로운 모듈의 state가 된다.
// src/modules/counter.js

// 초기 상태값
const initialState = {
  number: 0,
};

// 리듀서
const counter = (state = initialState, action) => {
  console.log(action);
  switch (action.type) {
		// PLUS_ONE이라는 case를 추가한다.
		// 여기서 말하는 case란, action.type을 의미한다.
		// dispatch로부터 전달받은 action의 type이 "PLUS_ONE" 일 때
		// 아래 return 절이 실행된다. 
    case "PLUS_ONE":
      return {
				// 기존 state에 있던 number에 +1을 더한다.
        number: state.number + 1,
      };

    default:
      return state;
  }
};

// 모듈파일에서는 리듀서를 export default 한다.
export default counter;

action이 {type : "PLUS_ONE"}이기 때문에, 리듀서 안에 있는 스위치문은 action.type을 조회한다. 그리고 그것이 일치하면 return 절이 실행되면서 새로운 state를 반환한다.


4. useSelector로 변경된 state값 접근하기

// src/App.js

import React from "react";
import { useDispatch, useSelector } from "react-redux";

const App = () => {
  const dispatch = useDispatch();

	// 👇 코드 추가
  const number = useSelector((state) => state.counter.number); 

  console.log(number); // 콘솔 추가
  return (
    <div>
			{/* 👇 코드 추가 */}
      {number}
      <button
        onClick={() => {
          dispatch({ type: "PLUS_ONE" });
        }}
      >
        + 1
      </button>
    </div>
  );
};

export default App;

0개의 댓글