S3 Unit 4. [React] 상태 관리

나현·2022년 11월 1일
0

학습일지

목록 보기
34/53
post-thumbnail

💡 이번에 배운 내용

  • Section3. 사용자 친화적이고 안전한 Web App을 만들 수 있다.
  • Unit4. React 상태 관리: 프론트엔드 개발에서 React 상태 관리를 보다 더 효율적으로 할 수 있는 방법에 대해서 학습한다.

느낀점

Redux를 공부하는 데 열심히 잘 따라왔지만, 바짝 집중하지 못하면 제대로 못할 수도 있겠다는 생각이 들었다.
그래서 실습도 잘 될 때까지 2번씩 하고 학습내용도 두세번씩 읽었다. 여기에 블로그까지 정리하니 어느 정도 이해는 된다.
react는 이렇게 할 때는 재밌도 있고 이해도 되고 실습도 잘 되었지만,
나중가서 처음부터 하려면 손이 막히는 경우가 많다. 코드가 안 나와!
그러므로 잘 아는 거라도 방심하지말고 복습해야 한다는 점을 여실히 느꼈다.
컴퓨터 언어가 자연어가 아닌 인공어지만, 그래도 언어라는 점을 들어 예전 언어학시간에 교수님이 해주신 말을 여기에 적용해 볼 수 있을 것 같다.
"어느 정도 문법을 배웠으면 자꾸 문법에 집착하지 말고, 잘 쓰는 문장을 자꾸 따라 읽고 외워!!"

키워드

Redux, state, Action 객체, Dispatch, Reducer, Store, useDispatch, useSelector


학습내용

Ch1. 상태 관리

프론트엔드 개발에서의 상태

상태(state)는 UI, 프론트엔드 개발에서 "동적으로 표현되는 데이터"이다.
이 상태를 다룰 때에는 Side Effect(부수 효과. 함수의 입력 외에도 함수의 결과에 영향을 미치는 요인)을 잘 고려해야 한다. 대표적인 Side Effect로 네트워크 요청, API 호출 등이 있다.
React로 개발할 때 이런 부수 효과를 최대한 줄이고 컴포넌트 단위로 개발하는 것이 좋다.
하지만 어쩔 수 없이 사용해야 될 때가 있다.
이러한 점을 반영하여 상태의 위치를 잘 선택해야 한다.

로컬 상태, 전역 상태

상태의 위치에 대한 내용은 공식 문서의 다음 링크에서도 잘 소개하고 있으므로 사전에 읽어보면 좋다.
🔗 React - React로 사고하기

상태를 구분하는 데에 따로 법칙이 있는 것은 아니나 상태는 크게 전역, 로컬 상태로 나뉜다.

  • 로컬 상태
    • 특정 컴포넌트 안에서만 존재하며 영향을 끼치는 상태
    • ex) 다른 컴포넌트와 데이터를 공유하지 않는 폼(form) 데이터(input box, select box 등)
    • 서로 다른 컴포넌트가 서로 다른 상태를 가지는 것, 즉 출처(source)가 달라도 된다.
  • 전역 상태
    • 전프로덕트 전체나 여러 가지 컴포넌트가 동시에 관리하는 상태
    • ex) 데이터 로딩 여부(로딩 중), 다크 모드 기능, 다국어 설정 기능, 히스토리 기능, Undo/Redo 기능 등
    • 서로 다른 컴포넌트가 같은 상태를 가지는 것, 즉 출처가 같아야 한다.
      이는 다른 말로 Single source of truth(신뢰할 수 있는 단일 출처) 원칙이다.

위 개념을 바탕으로 다음과 같은 원칙이 있다.

  • 데이터 무결성: 동일한 데이터는 항상 같은 곳에서 데이터를 가지고 와야 한다.

상태 사용시 생기는 문제점: Props Dirlling

Props Drilling은 상위 컴포넌트의 state를 하위 컴포넌트에서 사용하기 위해 계속 props를 통해 전달하는 현상을 의미한다.
이 과정에서 하위 컴포넌트가 더 깊은 수준으로 들어갈수록, 중간에 이 상태를 사용하지 않지만 강제로 props 속성을 사용해 state를 전달해야하는 컴포넌트가 생기게 된다.
만약 이 전달 횟수가 많아진다면 다음과 같은 문제가 발생한다.

  • 코드의 가독성이 떨어진다.
  • 코드의 유지보수가 힘들다.
  • state 변경시 Props 전달 과정에서 전달역할만 하는 컴포넌트들도 리렌더링된다. 이러면 웹 성능에 영향을 주게 된다.
    이 문제를 해결하기 위해 상태 관리 라이브러리를 사용할 수 있다.

상태 관리 라이브러리

Props Drilling의 문제점을 해결하기 위해 상태 관리 라이브러리를 사용할 수 있다.
상태 관리 라이브러리로 전역으로 상태를 저장하고 사용할 수 있다.
물론 상태 관리 라이브러리가 반드시 필요한 것은 아니므로 때에 따라 적절히 사용하도록 한다.

대표적인 상태 관리 라이브러리 중 Redux가 있으며, 여기서는 Redux를 위주로 다룰 예정이다.


Ch2. Redux (중요)

여러 컴포넌트가 존재하고 상,하위 컴포넌트 모두 같은 상태를 사용한다면
상태는 최상위 컴포넌트에 위치해야 한다.
그러나 만약 이 상태를 사용하는 컴포넌트가 많아질수록 다음과 같은 문제점이 생긴다.

  • 해당 상태를 직접 사용하지 않는 컴포넌트도 상태를 가지거나 props를 주고받아야 한다.
  • Props drilling이 발생한다.
  • 상태 끌어올리기를 여러 번 해야할 수 있다.
  • 애플리케이션이 복잡해지고 유지보수가 어렵다.

그러나 위에서 언급한 상태 관리 라이브러리 중 Redux를 사용하면 이 상태를 보다 효과적으로 관리할 수 있다.

Redux의 구조와 원리

Redux는 다음과 같은 순서로 상태를 관리한다.

  • Action 객체 : 변경될 상태에 대한 정보가 담긴 객체. 상태 변경 이벤트 발생시 생성된다.
  • Dispatch 함수 : Action 객체를 전달인자로 받아 Reducer 함수로 전달한다.
  • Reducer 함수 : Action 객체의 값을 확인하고, 그 값에 따라 Store에 있는 상태를 변경한다.
  • Store : 상태가 저장되어 있는 전역상태 저장소이다.

Redux 사용하기

Redux를 사용하는 방법은 아래와 같다.

1) Store 생성 후 Reducer 함수 할당하기
2) Reducer함수 생성하기
3) Action 객체 작성 및 생성하기
4) Dispatch함수로 Action 객체 전달하기
5) Redux Hooks 사용하기

각 과정은 다음 항목에서 자세히 살펴볼 예정이다.

1) Store 생성 후 Reducer 함수 할당하기

전역 상태 저장소를 만들기 위해 createStore 메서드를 불러와야 하며,
상태를 저장소에 저장해줄 reducer함수를 인자로 전달한다.

import { createStore } from 'redux';

//저장할 변수=createStore(임의의 reducer 함수명)
const store = createStore(myReducer);

2) Reducer함수 생성하기

Reducer함수는 인자가 두개로 첫번째 인자는 변경될 state, 두번째 인자는 action 객체이다.
Reducer는 Dispatch에서 전달받은 Action 객체를 확인하고,
그 값에 따라서 상태를 변경시킨다.
이 때, Reducer는 순수함수여야 하는데 이외의 방법으로 상태가 변경되서는 안되기 때문이다.

주로 아래의 action.type처럼 객체 안의 type값을 확인해 상태를 조정할 수 있다.
그리고 리턴한 상태는 Store에 저장된다.

const num = 0

// Reducer는 기존 상태를 받아 새로운 상태를 리턴하여 저장소에 저장한다.
// Reducer(state, action)
const counterReducer = (state = num, action) => {
  // Action 객체의 type 속성값에 따라 분기
  switch (action.type) {
    case 'INCREASE':
			return state + 1
    case 'DECREASE':
			return state - 1
    // 해당 되는 경우가 없을 시 기존 상태를 그대로 리턴
    default:
      return state;
	}
}

만약 여러 개의 Reducer를 사용하려면
아래와 같이 Redux의 combineReducers 메서드를 사용해서 하나의 Reducer로 통합한다.

import { combineReducers } from 'redux';

const rootReducer = combineReducers({
  myReducer,
  yourReducer,
  ...
});

3) Action 객체 작성 및 생성하기

Action객체의 형식은 아래와 같다.

//예시1)
{ type: 'INCREASE' }
//예시2)
{ type: 'SET_NUM', payload: 2 }

Action 객체를 작성할 때는 다음과 같은 몇가지 규칙이 있다.

  • type은 필수로 지정해야 한다.(객체가 어떤 동작을 하는지 명시)
  • type값 작성시 대문자와 Snake Case로 작성한다.
  • 구체적인 값을 전달해야 한다면 payload 를 작성한다.

이 Action은 보통 직접 작성하지 않고 아래처럼 생성함수를 만들어 사용하는 경우가 많다.
이를 액션(객체) 생성자(Action Creator)라고 한다.

//예시1)
const increase = () => {
  return {
    type: 'INCREASE'
  }
}
//예시2)
const setNum = (n) => {
  return {
    type: 'SET_NUM',
    payload: n
  }
}

4) Dispatch함수로 Action 객체 전달하기

Dispatch는 Reducer로 Action을 전달해주는 함수이다.
Action 객체를 전달인자로 받으며 Reducer를 호출한다.
사용법은 아래와 같다.

// Action 객체 직접 작성
dispatch( { type: 'SET_NUM', payload: 2 } );
// 액션 생성자 사용
dispatch( setNum(2) );

5) Redux Hooks 사용하기

컴포넌트와 redux의 state를 연결하기 위해 Redux Hooks를 사용한다.
Redux Hooks의 메서드는 React-Redux에서 제공하며 크게 두가지가 있다.

  • useDispatch()
    Action 객체를 Reducer로 전달해 주는 Dispatch 함수를 반환하는 메서드이다.
    위의 4)의 dispatch 함수도 useDispatch()를 사용해서 만든 것이다.
    한 번 더 정리하자면 아래와 같이 사용한다.
import { useDispatch } from 'react-redux'

const dispatch = useDispatch()
dispatch( increase() )
dispatch( setNum(2) )
  • useSelector()
    컴포넌트와 state를 연결하여 Redux의 state에 접근할 수 있게 해주는 메서드이다.
    useSelector는 인자로 콜백함수가 있으며,
    이 콜백함수의 전달인자(아래에서는 state)는 저장소에 있는 모든 state이다.
    콜백함수에서 이 state를 반환하여 아래와 같이 변수에 할당할 수 있다.
import { useSelector } from 'react-redux'

const num = useSelector(state => state)

Redux의 세 가지 원칙

Redux의 원칙을 아래와 같이 정리했다.

  1. Single source of truth
    동일한 데이터는 항상 같은 곳에서 가지고 와야 한다.
    즉, Redux의 데이터 저장소는 전역 상태 저장소인 Store만 있어야 한다.

  2. State is read-only
    상태는 읽기 전용이라는 의미다.
    React에서 상태갱신함수로만 상태를 변경할 수 있었던 것처럼, Redux의 상태도 직접 변경할 수 없다.
    Action 객체가 있어야만 상태를 변경할 수 있다.

  3. Changes are made with pure functions
    상태 변경은 순수함수로만 가능하다.
    상태를 변경하여 store에 저장하는 Reducer함수는 상태가 엉뚱한 값으로 변경되는 일이 없도록 순수함수로 작성되어야한다.




참고 자료 및 추가학습

1. Redux 공식 문서
https://redux.js.org/

2. React Redux 공식 문서
https://react-redux.js.org/

3. flux pattern
https://facebook.github.io/flux/docs/in-depth-overview/
Flux 패턴이란 데이터 흐름에 대한 애플리케이션 아키텍쳐 중 하나이다.
이 패턴은 기존 MVC모델에 기반한 양방향 데이터 흐름의 문제를 해결하기 위해 페이스북에서 고안했다.
Flux 패턴에서는
action -> dispatcher -> store -> view
이런 흐름으로 데이터가 단방향으로 흐르도록 한다.
이름도 그렇고 모양새도 Redux와 참으로 유사함을 알 수 있다.
기존 문서가 짧지도 않고 40분이 넘는 동영상에 영문이므로 쉽게 이해 수 있는 또다른 참고 문서들을 아래에 정리했다.

profile
프론트엔드 개발자 NH입니다. 시리즈로 보시면 더 쉽게 여러 글들을 볼 수 있습니다!

0개의 댓글