Space
article thumbnail
Published 2023. 7. 27. 12:24
[Redux] Redux Redux
반응형

Before you learn

React 문법(JSX)

React State

React Props

반응형

Props Drilling

 

상위 컴포넌트의 State를 props를 통해 전달하고자 하는 컴포넌트로 전달하기 위해

그 사이는 props를 전달하는 용도로만 쓰이는 컴포넌트들을 거치면서 데이터를 전달하는 현상을 의미합니다.

 

● 단점

   ○ 코드의 가독성이 나빠진다.

   ○ 코드의 유지보수가 힘들어진다.

   ○ state 변경 시 props 전달 과정에서 불필요하게 관여된 컴포넌트들 또한 리렌더링이 발생한다.

      (따라서, 웹성능에 악영향을 줄 수 있다.)


Redux

상태 관리 라이브러리

 

Redux 3가지 원칙

Single source of truth(신뢰할 수 있는 단일 출처)

     -> 데이터 무결성을 위해 동일한 데이터는 항상 같은 곳에서 데이터를 가져와야 한다.

 

State is read-only (상태는 읽기 전용이다.)

     -> React에서 상태갱신함수로만 상태를 변경할 수 있었던 것 처럼, Redux의 상태도 직접 변경할 수 없다.

           즉, Action 객체가 있어야만 상태를 변경할 수 있다.

 

Changes are made with pure functions (변경은 순수함수로만 가능하다.)

     -> 상태가 엉뚱한 값으로 변경되는 일이 없도록 순수함수로 작성되어야 하는 Reducer와 연결되는 원칙이다.


장점

   ○ 전역 상태 저장소를 제공한다.

   ○ Props drilling을 해결해준다.

   ○ 상태의 출처를 파악하기 쉬워지므로 코드의 유지보수가 좋아진다. 


동작 순서

Action -> Dispatch -> Reducer -> Store 순으로 데이터가 단방향으로 흐른다.

 

이론)

1. 상태가 변경되어야 하는 이벤트가 발생하면, 변경될 상태에 대한 정보가 담긴 Action 객체가 생성된다.

2. 이 Action 객체는 Dispatch 함수의 인자로 전달된다.

3. Dispatch 함수는 Action 객체를 Reducer 함수로 전달해준다.

4. Reducer 함수는 Action 객체의 값을 확인하고, 그 값에 따라 전역 상태 저장소(Store)의 상태를 변경한다.

5. 상태가 변경되면, React는 화면을 리렌더링한다.

 

예시)

1. 사용자가 상품 추가 버튼을 클릭한다.

2. 상품 추가에 대한 Action 객체가 생성된다.

3. 해당 Action 객체가 Dispatch를 통해 Reducer로 전달된다.

4. Reducer가 Action 타입에 따라 분기하여 새로운 State를 리턴한다.

5. 해당 State가 Store에 업데이트 된다.

6. Store에 변경이 생기면 useSelector를 통해 리액트에도 반영된다.

 

Redux 개발 환경 구성

# Redux 설치
npm i redux

# React-Redux 설치 (useDispatch, useSelector 사용하기 위해)
npm i react-redux

Action

● Action은 말 그대로 어떤 액션을 취할 것인지 정의해 놓은 객체입니다.

type은 필수 / payload는 옵션이다. (대문자Snake Case로 작성한다.)

// 타입을 상수로 줘서 같은 타입명을 사용하지 않도록 한다.
const INCREASE = 'INCREASE';
const SET_NUMBER = 'SET_NUMBER';

// payload가 필요 없는 경우
const increase = () => {
  return {
    type: INCREASE
  }
}

// payload가 필요한 경우
const setNumber = (num) => {
  return {
    type: SET_NUMBER,
    payload: num
  }
}

Dispatch

Action 객체를 reducer에 전달해주는 함수

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

export default function App() {
  const dispatch = useDispatch();
  
  const counter = useSelector( (state) => state );
    
  return (
    <div className="App">
      <p>지금 숫자는 : {counter} 입니다.</p>
      <button onClick={() => dispatch(increase())}>더하기</button>
      <button onClick={() => dispatch(decrease())}>빼기</button>
    </div>
  );
}

Reducer

Action에 따라 State를 변경하는 함수

reducer는 순수함수이어야 한다.

// 하나의 reducer 사용하는 경우
const initialNum = 100;

function reducer(state = num, action) {
  if (action.type === 'INCREASE') {
    return state +1;
  } else if (action.type === 'DECREASE') {
    return state -1;
  } else {
    return state
  }
}
// rootReducer 사용하는 방법
// counterReducer, anyReducer가 만들어진 상태라고 가정한다.
import { combineReducers } from 'redux';

const initialCount = 100;
const initialNum = 50;

function conterReducer(state = initialCount, action) {  // reducer
  if (action.type === 'INCREASE') {
    return state +1;
  } else if (action.type === 'DECREASE') {
    return state -1;
  } else {
    return state;
  }
}

function anyReducer(state = initialNum, action) {  // reducer
  ...
}

const rootReducer = combineReducers({  // reducer들을 묶어준다.
  counterReducer,
  anyReducer,
  ...
});

Store

State를 관리하는 저장소

import { createStore } from 'redux';

const store = createStore(rootReducer)

const counter = useSelector((state) => state.counterReducer)
const any = useSelector((state) => state.anyReducer)

export default function App() {
   return (
      <Counter>Count : {counter} </Counter>
        <div>
          <CounterButton onClick={()=>dispatch(increase())}>+</CounterButton>
          <CounterButton onClick={()=>dispatch(decrease())}>-</CounterButton>
        </div>
        ...
   )
}

 

 

Redux알아보는 시간이었습니다.

틀린 내용은 댓글로 알려주시면 감사하겠습니다.

 

 

반응형
profile

Space

@Space_zero

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!