Unit4 회고

YEN J·2022년 11월 2일
0

code states

목록 보기
30/43

[React]상태 관리

상태 관리

🔆 전역 상태 관리

상태🧐

상태(state)UI에 동적으로 표현될 데이터를 의미한다. 즉, 보여지는 화면에서 변화될 수 있는 데이터를 의미하는데 이 때 state는 props를 통해 전달되지 않으며 시간이 지나 변화될 수 있고 컴포넌트 안에 있는 다른 state나 props를 통해 계산이 가능하지 않아야 한다는 조건을 가진다. 이를 통해 컴포넌트 안에는 최소한의 상태를 만들게 된다.

Side effect😎

Side effect함수(컴포넌트)의 입력 외에도 함수의 결과(출력)에 영향을 미치는 요인으로 side effect의 대표적인 예시로 네트워크 요청(API 호출)이 있다. 함수를 정의할 때 side effect는 최대한 배제할 수 있도록 작성해야 하지만 네트워크 요청과 같이 불가피하게 side effect에 의존하는 경우도 있는데 이 경우 상태를 잘 고려하여 만들어야 한다.

  • React로 사고하기
    • UI를 컴포넌트 계층 구조로 나누기
    • React로 정적인 버전 만들기
    • UI state에 대한 최소한의 (하지만 완전한) 표현 찾아내기
    • state가 어디에 있어야 할 지 찾기
    • 역방향 데이터 흐름 추가하기
      React로 사고하기

상태의 두 가지 구분

  • 로컬 상태: 특정 컴포넌트 안에서만 관리되는 상태
  • 전역 상태: 프로덕트 전체 혹은 여러 컴포넌트에서 관리되는 상태
    • 데이터 무결성을 위한 원칙(전역 상태에서도 적용)
      • Single source of truth(신뢰할 수 있는 단일 출처)
      • 동일한 데이터는 항상 같은 곳에서 데이터를 가지고 온다

상태 관리 라이브러리

  • 상태를 관리하는 라이브러리는 React Context, Redux, MobX 등이 있음
  • 상태 관리 라이브러리 사용 시 이점
    • 전역 상태를 위한 저장소 제공
    • Props drilling 이슈 해결
  • 상태 관리 툴은 장단점이 명확하므로 잘 인지한 뒤 사용할 것!

🔆 Props Drilling

Props Drilling❓

Props Drilling이란 상위 컴포넌트의 state를 특정 하위 컴포넌트로 전달하기 위해 그 사이에 위치한 컴포넌트들은 props를 전달하는 용도로만 쓰이게 되는 현상을 말한다.

  • Props Drilling의 문제점

    • 코드의 가독성이 나빠짐
    • 코드의 유지보수가 어려워짐
    • state 변경 시 사이에 위치한 컴포넌트들의 불필요한 리렌더링으로 인해 웹성능에 악영향을 미침
  • Props Drilling 이슈 해결 방법

    • 컴포넌트와 관련 있는 state는 최대한 가까운 곳에 유지
    • 상태 관리 라이브러리 사용

Redux

🔆 Redux의 필요성

Redux는 왜 필요할까❓

깊이 3단계 트리 구조의 컴포넌트들로 구성된 애플리케이션의 경우 각기 다른 부모를 가진 가장 하위의 2개의 컴포넌트들만 하나의 상태를 공유한다고 가정해보자. 이 때 2개의 컴포넌트가 상태를 공유하기 위해 공통으로 공유할 수 있는 최상위 컴포넌트에 하나의 상태를 위치시킨다. 이 경우에는 비교적 단순해 보일 수 있지만 이보다 훨씬 더 높은 단계의 트리 구조를 가진 애플리케이션의 경우라면 어떠한 일이 발생할까?

  • 사이에 있는 컴포넌트는 불필요한 상태 데이터를 가지게 됨
  • 상태를 끌어올리고 props를 내려주는 과정의 반복을 거쳐야 함
  • 컴포넌트의 구조가 바뀔 경우 데이터 흐름 자체가 바뀔 수 있음

❗️Redux는 하나의 저장소인 Store에서 전역 상태를 관리하여 문제를 해결❗️

🔆 Redux 상태 관리 방식

Redux가 상태를 관리하는 순서

  1. 상태가 변경되어야 하는 이벤트 발생 시, 변경될 상태 정보가 담긴 Action 객체 생성
  2. Aciton 객체가 Dispatch 함수 인자로 전달
  3. Dispatch 함수는 Action 객체를 Reducer 함수로 전달
  4. Reducer 함수는 Action 객체의 값을 확인 후, 값에 따라 전역 상태 저장소인 Store의 상태를 변경
  5. 상태가 변경 시, React는 화면 리렌더링
  • Redux의 데이터 흐름은 단방향
    • Action → Dispatch → Reducer → Store 순의 흐름
  • Redux는 React에 종속된 라이브러리가 아닌 독립적인 라이브러리라는 것을 기억할 것

🔆 Redux를 구성하는 개념

Store🗄

  • 상태가 관리되는 유일한 저장소의 역할로 redux 앱의 state가 저장되어 있는 공간
  • 형식
  import { createStore } from 'redux';

  const store = createStore(Reducer함수);

Reducer🗂

  • Dispatch에게서 전달받은 Action 객체의 type에 따라 상태를 변경시키는 함수

❗️주의❗️
Reducer는 입력에 따라 출력이 이루어지는 순수함수여야 함

  • Reducer 함수의 첫 번째 인자에는 기존 state, 두 번째 인자에는 action 객체를 전달
    • state에는 default value를 설정해주어야 하며 그렇지 않을 경우 undefined 할당
  • Reducer 함수에 의해 변경된 state는 전역 변수 저장소인 Store에 저장
  • 여러 개의 Reducer를 사용하는 경우
    • 애플리케이션의 규모가 커지고 복잡해질 경우 여러 개의 Reducer를 사용할 수 있다
    • combineReducer를 사용해 하나의 Reducer로 병합 가능
    • 여러 Reducer를 combineReducer를 통해 하나로 병합하는 과정은 여러 컴포넌트가 하나의 큰 컴포넌트의 구성요소과 되는 과정과 비슷함
  • 형식
  const Reducer함수 = (state = 초기상태, action) => {

    // Action 객체의 type 값에 따라 분기하는 switch 조건문
    switch (action.type) {

      case 경우1:
              return 경우1일 때, 변화하는 상태

      case 경우2:
              return 경우2일 때, 변화하는 상태

      // 해당 되는 경우가 없는 case에는 기존 상태를 그대로 리턴
      default:
        return state;
      }
  }

Action🤸🏻

  • 경우에 따라 수행할 각각의 액션을 정해놓은 객체
  • 형식
  // payload가 필요 없는 경우
  { type: 'CASE_NO_PAYLOAD' }

  // payload가 필요한 경우
  { type: 'CASE', payload: 5 }
  • type은 Action 객체가 수행할 동작을 명시하기 때문에 필수로 지정해줄 것

    • type 작성 시, 대문자와 snake case(공백을 밑줄로 대체하는 규칙)로 작성
  • payload는 필요에 따라 작성

  • 보통 Action을 직접 작성하기보다 Action 객체를 생성하는 함수를 만들어서 사용하는 데 이러한 함수를 액션 생성자(Action Creator)라고 함

    • 형식
    // payload가 필요 없는 경우
    const caseNoPayload = () => {
      return {
        type: 'CASE_NO_PAYLOAD'
      }
    }
    
    // payload가 필요한 경우
    const case = (인자) => {
      return {
        type: 'CASE',
        payload: 인자
      }
    }

Dispatch📤

  • Reducer로 Action을 전달해주는 함수
  • Dispatch의 전달인자로 Action 객체가 전달
  • 형식
  // Action 객체를 직접 작성하는 경우
  dispatch( { type: 'CASE_NO_PAYLOAD' } );
  dispatch( { type: 'CASE', payload: 5 } );

  // 액션 생성자(Action Creator)를 사용하는 경우
  dispatch( caseNoPayload() );
  dispatch( case(5) )

🔆 Redux hooks

Action, Dispatch, Reducer, Store의 개념을 연결시키기 위해 이용하는 함수

useDispatch()

  • Dispatch 함수를 반환하는 메서드
  • Dispatch 함수는 Action 객체를 Reducer로 전달해주는 역할을 수행
  • 형식
  import { useDispatch } from 'react-redux'

  const dispatch = useDispatch()
  dispatch( caseNoPayload() )

  dispatch( case(5) )

useSelector()

  • 컴포넌트와 state를 연결하여 Redux의 state에 접근할 있게 해주는 메서드

  • 형식

// Redux Hooks 메서드는 'redux'가 아니라 'react-redux'에서 불러옴
import { useSelector } from 'react-redux'
const state = useSelector(state => state)

🔆 Redux의 세 가지 원칙

1. Single source of truth🗄

  • 동일한 데이터는 항상 같은 곳에서 가지고 와야 한다
  • Redux에 데이터를 저장하는 공간은 Store 하나뿐이라는 개념과 연결되는 원칙

2. State is read-only🤸🏻

  • 상태는 읽기 전용
  • Action 객체가 있어야만 상태를 변경할 수 있다는 개념과 연결되는 원칙

3. Changes are made with pure functions🗂

  • 변경은 순수함수로만 가능하다
  • 순수함수로 작성되어야 하는 Reducer와 연결되는 원칙

참고
Redux

<오늘의 일기>
이번 유닛은 상태 관리를 복습해보고 상태 관리를 도와주는 라이브러리인 Redux에 대해 공부했다. 처음 Redux를 접했을 때 사실 상태라는 개념 자체도 어려웠었는데 Redux를 봤을 때 '이걸 도대체 어떻게 적용하지?' 라는 걱정에 사로잡혔었다. 지금도 역시 Redux를 자유자재로 사용할 수 있는 수준은 아니지만 그래도 실습이나 과제를 통해 Redux의 필요성이나 데이터 흐름에 대해서는 확실하게 알게 되었다.
이번 페어분은 페어와 소통을 원활하게 하기 위해 노력하시는 분 같았다. 사실 페어 활동할 때 나에게는 그런 부분들이 가장 어렵게 느껴졌는데 이번 페어 활동을 하면서 앞으로는 페어 활동을 할 때 너무 기다리는 것보다 다가가기 위해 노력해봐야겠다는 생각이 많이 들었다.
이번 유닛은 특히 부트캠프에 들어오면 다짐한 목표 중에 하나가 협업 능력을 키우는 것이었던 만큼 부트캠프의 남은 기간 동안은 지금의 나보다는 조금 더 적극적인 자세를 가져야겠다고 다짐하게 된 유닛이었다.

0개의 댓글