공부기록/[강의노트] Udemy React 완벽가이드 201~300

# 243 [udemy React 완벽 가이드 노트] 리액트용 리덕스 스토어 만들기

Jenner 2022. 10. 12. 17:47

프로젝트 폴더에 

 

npm install
npm install redux react-redux

를 차례대로 입력한다. 

 

redux는 react와 연동이 잘 안될 수도 있기 때문에 

react-redux 서드파티 라이브러리를 같이 install해준다. 

 

 

앞서 배웠던 reducer 함수와 store를 만든다.

 

 

import { createStore } from "redux";

const counterReducer = (state = { counter: 0 }, action) => {
  if (action.type === "increment") {
    return { counter: state.counter + 1 };
  }

  if (action.type === "decrement") {
    return { counter: state.counter - 1 };
  }

  return state;
};
const store = createStore(counterReducer);

 

이제 리액트 앱과 리덕스 스토어를 연결해보자. 

 

export default store;

 

export함으로써 다른 파일에서도 사용할 수 있게 된다. 

store는 하나밖에 없다. 

store를 한 번만 제공하면 된단 이야기다. 

그런데 store를 제공하는 것이 무슨 의미일까?

 

 

 

 

리액트 앱에 리덕스 store 제공하기


 

전체 앱을 렌더하는 index.js로 간다. 

리액트 애플리케이션에서 가장 높은 레벨의 파일이다. 

(컴포넌트 트리의 가장 위쪽)

 

 

react-redux에서 Provider를 import한다.  

App컴포넌트를 Provider 컴포넌트로 랩한다. 

랩된 컴포넌트와 그 자손 컴포넌트들만이 리덕스에 접근할 수 있다. 

 

 

import { Provider } from "react-redux";

 

컴포넌트의 대부분이 스토어에 접근하려면

지금과같이 가장 높은 레벨에서 제공해야 한다. 

 

react-redux와 react에 어떤 스토어를 제공하고 싶은지 말하지 않고,

(store 폴더의 index.js파일이라고 말해 주지 않는다)

 

store를 import할 것이다.  

import store from "./store/index";

 

그리고 Provider 컴포넌트에 store 프롭의 밸류로 import한 store를 넣어준다. 

 

  <Provider store={store}>

이 것이 리덕스 스토어를 리액트 앱에 제공하는 코드다. 

이렇게 함으로써 앱컴포넌트와 다른 자식 컴포넌트는

스토어에 탭 될 수 있다. 

즉, 스토어 밖으로 데이터를 가져올 수 있고, 데이터를 구독할 수 있고, 액션을 디스패치할 수도 있게 된다. 

 

 

 

 

리액트 컴포넌트에서 리덕스 데이터 사용하기


이제 데이터를 App컴포넌트가 아닌 counter 컴포넌트에서 사용해보자.

Counter 컴포넌트에서 react-redux로부터 useSelector 훅을 임포트해오자. 

리액트 리덕스 팀이 만든 커스텀 훅이다. 

 

import { useSelector } from 'react-redux'

useStore 훅도 있다. 스토어에 바로 접근할 수 있는 훅이다. 

하지만 useSelector가 더 편하다. 

자동으로 store가 관리하는 state의 일부를  선택하게 해주기 때문이다. 

 

그런데 클래스 기반 컴포넌트를 사용한다면

connect 함수를 wrapper로 대신 사용할 수 있다. 

클래스 컴포넌트 근처에서 클래스 컴포넌트를 스토어에 연결한다. 

 

일단 먼저 useSelector먼저 사용해 보도록 하자. 

 

useSelector

 

 

const Counter = () => {
  useSelector();

 

 

Counter 함수 안에 useSelector를 호출한다. 

useSelector에는 함수를 전달한다. 

전달하는 함수는 react-redux에 의해 실행될 것이며 

함수가 어떤 데이터를 스토어에서 추출할지 결정할 것이다.

 

 

               지금은 store의 데이터 구조는 작고 단순하지만, 

               더 큰 store가 되면 데이터에는 중첩되어있는 많은 객체들이 있을 것이다. 

               전체 state 객체에서 일부만 받아오는 작업을 할 수 있게 되는 것이다. 

 

 

 그러려면 useSelector에 함수를 건네줘야 한다.  

함수는 리덕스가 관리하는 state를 받을 것이다. 

 

const Counter = () => {
  useSelector(state => state.counter);

 

추출하고 싶은 일부 state를 return 한다. 

 

 

이 함수는 react-redux에 의해 실행될 것이다. 

redux에 state를 보내어 

이 함수로 데이터를 관리할 것이다. 

 

이 코드를 실행해서 컴포넌트에서 필요한 state의 일부를 

되돌려 받을 것이다. 

그것은 counter 변수에 할당한다.

const Counter = () => {
  const counter = useSelector(state => state.counter);

 

리덕스가 관리하는 counter다.

 

useSelector를 사용하면 

컴포넌트를 위해서 리덕스 스토어에 react-redux가 자동으로 구독을 설정한다. 

 

리덕스 스토어에서 데이터가 바뀔 때마다

컴포넌트가 업데이트 될 것이며 

자동으로 최신 카운터를 받을 것이다. 

 

자동으로 리덕스 스토어가 바뀌면 

컴포넌트 함수가 다시 실행될 것이다. 

 

counter는 그래서 항상 최신의 counter가 된다. 

이 counter를 jsx코드에서 사용하면 된다. 

 

 

 

action을 dispatch하여 데이터를 바꿔보자


 

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

useDispatch  hook을 import 한다

 

useDispatch는 Redux store에 대한 action을 보낸다. 

 

여기서 dispatch에 전달하는 type 프로퍼티는

reducer함수에서 사용하는 식별자 중 하나여야 한다. 

 

그리고 각각의 increment와 decrement Handler 함수를 button에 연결시켜 준다. 

 

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

import classes from "./Counter.module.css";

const Counter = () => {
  const dispatch = useDispatch();
  const counter = useSelector(state => state.counter);

  const incrementHandler = () => {
    dispatch({ type: "increment" });
  };

  const decrementHandler = () => {
    dispatch({ type: "decrement" });
  };

  const toggleCounterHandler = () => {};

  return (
    <main className={classes.counter}>
      <h1>Redux Counter</h1>
      <div className={classes.value}>{counter}</div>
      <div>
        <button onClick={incrementHandler}>Increment</button>
        <button onClick={decrementHandler}>Decrement</button>
      </div>
      <button onClick={toggleCounterHandler}>Toggle Counter</button>
    </main>
  );
};

export default Counter;

 

 

 

 

 

 

 

 

Increment나 Decrement 버튼을 누를 때마다

1씩 증가 혹은 감소한다.