[5주차] React 숙련 강의 내용 정리 (3) - redux : useSelector, useDispatch

voyager 999·2024년 1월 25일

React

목록 보기
9/27

여기까지 오기 전에 가상DOM 이름만 몇 번 접했을 때는 너무 어렵고 복잡한 개념일 거라고 생각했는데, 강의를 듣고 공부해보고 나니 흥미로운 개념이라는 생각이 들었다. 이런 걸 처음 고안해 낸 사람은 그야말로 천재다🥹


DOM & Virtual DOM

가상DOM은 실제 DOM과 구조가 동일한 형태의 복사본으로, 객체 형태로 메모리에 저장된다. 실제 DOM을 조작하는 것보다 javascript 객체를 변경하는 작업이 더 가볍기 때문에 더 빠르게 조작을 수행할 수 있다.

  • diffing
    state가 변경될 때 가상DOM을 비교하여 어느 엘리먼트에 변화가 일어났는지 파악한다.

  • reconciliation
    파악이 끝나면 해당 부분만 실제 DOM에 적용시킨다. 변경 사항은 Batch Update된다. --> 5개의 변경사항이 있어도 1회만 렌더링된다.


Redux

전역 상태관리 라이브러리. 중앙 state 관리소 역할을 하는 패키지(라이브러리)이다. Redux를 사용하면 State를 공유할 때 부모-자식 관계가 아니어도 되기 때문에 의미 없는 drilling을 거치지 않아도 된다.

특정 컴포넌트 안에서만 필요한 state는 지역 상태(Local state)로 관리하고, 어디서든 접근/제어하고 싶은 state는 전역 상태(Global state)로 관리한다.


Redux 설정

1. 리덕스 패키지 설치하기

npm i redux react-redux
yarn add redux react-redux

2. ./redux / config / configStore.js
중앙 state 관리소를 아래처럼 기본 셋팅해준다. rootReducer 변수의 combineReducers의 인자로는 modules 폴더 안에 있는 state들을 key-value pair 형태로 들어가게 될 것이다.

import { createStore } from "redux";
import { combineReducers } from "redux";

const rootReducer = combineReducers({
   key: value })
const store = createStore(rootReducer);

export default store;

3. index.js
store를 사용하기 위한 코드를 작성해준다. store를 상단에서 import해주고, Provider로 App 컴포넌트를 감싸준다.

...생략

import { Provider } from 'react-redux';
import store from './redux/config/configStore';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <Provider store={store}> // <---여기
    <App />
  </Provider>

);

...생략

4. Modules 폴더 안에서 state 만들기
useState를 사용할 때 초깃값을 설정해줬던 것처럼 counter.js에서 카운터의 초깃값을 0으로 설정해준다.

초기 상탯값 아래에는 state에 변화를 일으키는 함수인 Reducer 를 만들어준다. 이 함수는 state와 action을 인자로 받는다.

const initialState = {
    number: 0, // <---초깃값 설정
};

const counter = (state = initialState, action) => {
   switch (action.type) { // <---reoducer 설정
      default:
         return state;
    }
}

export default counter;

5. 만들어진 reducer를 Store에 모아주기

import { createStore } from "redux";
import { combineReducers } from "redux";

const rootReducer = combineReducers({
   counter; counter }) // <---여기
const store = createStore(rootReducer);

export default store;

useSelector로 store 접근하기

store에 접근하여 counter 값을 읽어오고 싶은 위치에서 Redux의 Hooks인 useSelector를 사용한다.

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

function App() {

  const counter = useSelector((state) => {
    return state.counter; // <--- 여기
  });
  
  console.log("counter -->", counter.number);

useDispatch로 state 변경하기

dispatchaction(type, payload) 을 store에 던져주고, store는 받은 action의 타입에 따라 state를 변경한다.

1. reducer에 action type 설정하기

const initialState = {
    number: 0,
};

const counter = (state = initialState, action) => {
    switch (action.type) {
        case "PLUS_ONE": // <---여기
            return {
                number: state.number + 1,
            }

        case "MINUS_ONE": // <---여기
            return {
                number: state.number - 1,
            }
        default:
            return state;
    }
}

export default counter;

2. dispatch로 action 던져주기
컴포넌트에 useDispatch를 import하고, dispatch를 가져온 다음, 함수가 실행되는 곳에 dispatch를 넣어준다. 이 때 dispatch()의 인자에는 위에서 미리 설정해 둔 action 객체를 넣어주면 된다.

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

function App() {

  const counter = useSelector((state) => {
    return state.counter;
  });

  const dispatch = useDispatch(); // <--Dispatch 가져오기

  console.log("counter -->", counter.number);

  return <>
  <div> 현재 카운트 : {counter.number}  </div>
  <button onClick={() => {
    dispatch({
      type: 'PLUS_ONE', // <--action 객체 넣어주기
    })
  }}>+</button>
  <button onClick={() => {
    dispatch({
      type: 'MINUS_ONE', // <--action 객체 넣어주기
    })
  }}>-</button>
  </>
}

export default App;

0개의 댓글