Redux 시작하기

Jemin·2023년 6월 24일
0

지식 공유

목록 보기
21/53
post-thumbnail
post-custom-banner

지금까지 프론트 개발을 하면서 Recoil과 Zustand는 사용해봤는데 Redux는 사용해본 적이 없어서 개인 프로젝트에 사용해보기로 했다.

당연히 공식 문서를 읽는 것 부터 학습을 시작했다.

[공식 문서] Redux

Redux란

Redux는 "Action"이라는 이벤트를 사용하여 애플리케이션 상태를 관리하고 업데이트하기 위한 패턴 및 라이브러리다.

상태가 예측 가능한 방식으로만 업데이트될 수 있도록 하는 규칙과 함께 전체 애플리케이션에서 사용해야 하는 상태에 대한 중앙 집중식 저장소 역할을 한다.

Redux는 애플리케이션의 여러 부분에서 필요한 상태인 "전역" 상태를 관리하는데 도움을 준다.

Redux 개념

Redux는 Flux 아키텍처의 개념을 기반으로 설계되었다. Flux는 단방향 데이터 흐름을 가지는 아키텍처로서, 데이터의 변화를 예측 가능한 방식으로 관리하고 컴포넌트 간의 의존성을 줄이는 데 초점을 두고 있다.

React에서의 단방향 데이터 흐름을 보자면

  • state는 특정 시점의 앱 상태를 설명한다.

  • UI(View)는 해당 상태를 기반으로 렌더링된다.

  • 어떤 일이 발생(Actions)하면 발생한 상황에 따라 state가 업데이트 된다.

  • 새로운 상태에 따라 UI가 다시 렌더링된다.

그러나 동일한 상태를 공유하고 사용해야 하는 여러 구성 요소가 있는 경우, 단순성이 무너질 수 있다. 이 문제는 부모 구성 요소로 상태를 들어 올려서 해결할 수 있지만 항상 도움이 되는 것은 아니다.

쉽게 설명하자면 다수의 컴포넌트가 state를 공유해야하는 상황을 해결하기 위해 부모 컴포넌트에서 state를 관리해 state가 필요한 컴포넌트에 props로 전달한다는 말이다.

이를 더 효율적으로 해결하기 위해 공유 상태를 추출해서 구성 요소 트리 외부의 중앙 위치에 배치한다. 이를 통해 모든 구성 요소는 트리의 위치에 관계없이 상태에 접근할 수 있게된다.

이것이 Redux의 기본 아이디어다. Redux는 액션(Action), 리듀서(Reducer), 스토어(Store) 등의 핵심 개념으로 구성되어 있다. 액션은 상태 변경을 나타내는 객체이고, 리듀서는 액션을 기반으로 새로운 상태를 만들어내는 함수다. 스토어는 애플리케이션의 전역 상태를 관리하는 객체로서, 상태의 변화를 추적하고 컴포넌트에 전달한다.

Redux의 데이터 흐름

Redux의 경우 단방향 데이터 흐름보다 단계를 더 자세하게 나눌 수 있다.

  • 초기 설정
    • Redux 저장소는 루트 리듀서 기능을 사용하여 생성된다.
    • 스토어는 루트 리듀서를 한 번 호출하고 반환 값을 초기 state값으로 저장한다.
    • UI가 처음 렌더링되면 UI 구성 요소는 Redux 스토어의 현재 상태에 접근하고 해당 데이터를 사용하여 무엇을 렌더링할지 경정한다. 또한, 이후 업데이트를 구독하여 상태가 변경되었는지 알 수 있다.
  • 업데이트
    • 앱에서 무언가 발생한다. 예를 들어, 사용자가 버튼을 클릭하는 경우다.
    • 앱 코드는 액션을 Redux 스토어에 디스패치(dispatch)한다. 예를 들어, dispatch({type: "counter/increment"})와 같이 액션을 디스패치한다.
    • 스토어는 이전 상태와 현재 액션을 가지고 리듀서 함수를 다시 실행하고, 반환 값을 새로운 상태로 저장한다.
    • 스토어는 구독(subscribe)한 UI의 모든 부분에게 스토어가 업데이트되었다고 알린다.
    • 스토어의 데이터를 필요로하는 각 UI 컴포넌트는 필요한 상태 부분이 변경되었는지 확인한다.
    • 데이터가 변경된 컴포넌트는 새로운 데이터로 화면을 갱신하기 위해 강제로 리렌더링된다.

이러한 과정을 통해 Redux는 앱에서 발생하는 상태 변화를 관리하고, 변경된 데이터를 UI에 반영하여 화면을 업데이트하는 역할을 수행한다.

미들웨어

Redux에는 미들웨어(Middleware)라는 개념이 존재한다. Redux로 상태 관리를 할때에는 Reducer 함수를 사용한다. Redux의 미들웨어를 사용하면 액션 객체가 리듀서에서 처리되기 전에 우리가 원하는 작업들을 수행할 수 있다.

  • 특정 조건에 따라 액션이 무시되게 만들 수 있다.

  • 액션을 콘솔에 출력하거나, 서버쪽에 로깅을 할 수 있다.

  • 액션이 디스패치 됐을 때 이를 수정해서 리듀서에게 전달되도록 할 수 있다.

  • 특정 액션이 발생했을 때 이에 기반하여 다른 액션이 발생되도록 할 수 있다.

  • 특정 액션이 발생했을 때 특정 자바스크립트 함수를 실행시킬 수 있다.

미들웨어는 주로 비동기 작업을 처리할 때 많이 사용된다.

유용한 함수와, Hooks

connect 함수를 사용해 리덕스의 상태 또는 액션 생성 함수를 컴포넌트의 props로 받아올 수 있으며, useSelector, useDispatch, useStore 와 같은 Hooks를 사용하면 손쉽게 상태를 조회하거나 액션을 디스패치할 수 있다.

connect 함수와 useSelector 함수에는 내부적으로 최적화가 잘 이루어져있어서 실제 상태가 바뀔때만 컴포넌트가 리렌더링된다.

하나의 커다란 상태

Redux에서는 모든 클로벌 상태를 하나의 커다란 상태 객체에 넣어서 사용하는 것이 필수다.

Redux의 3가지 규칙

Redux를 프로젝트에서 사용하게 될 때 알아두고, 꼭 지켜야 할 3가지 규칙이 있다.

하나의 애플리케이션 안에는 하나의 스토어

하나의 애플리케이션에선 단 한개의 스토어를 만들어서 사용한다. 여러개의 스토어를 사용하는 것은 사실 가능하기는 하나, 권장되지 않는다. 특정 업데이트가 너무 빈번하게 일어나거나, 애플리케이션의 특정 부분을 완전히 분리시키게 될 때 여러개의 스토어를 만들 수도 있다. 하지만 그렇게 하면, 개발 도구를 활용하지 못하게 된다.

상태는 읽기전용

React에서 state를 업데이트 해야할 때, setState를 사용하고, 배열을 업데이트 해야 할 때는 배열 자체에 push를 직접 하지 않고, concat 같은 함수를 사용하여 기존의 배열은 수정하지 않고 새로운 배열을 만들어서 교체하는 방식으로 업데이트를 한다.
엄청 깊은 구조로 되어있는 객체를 업데이트를 할 때도 마찬가지로, 기존의 객체는 건드리지 않고 Object.assign 을 사용하거나 spread 연산자를 사용하여 업데이트 하곤 한다.

Redux도 마찬가지다. 기존의 상태는 건드리지 않고 새로운 상태를 생성하여 업데이트 해주는 방식으로 해주면, 나중에 개발자 도구를 통해서 뒤로 돌릴 수도 있고 다시 앞으로 돌릴 수도 있다.

Redux에서 불변성을 유지해야 하는 이유는 내부적으로 데이터가 변경 되는 것을 감지하기 위하여 shallow equality 검사를 하기 때문이다. 이를 통하여 객체의 변화를 감지할 때 객체의 깊숙한 안쪽까지 비교를 하는 것이 아니라 겉핥기 식으로 비교를 하여 좋은 성능을 유지할 수 있다.

리듀서는 순수한 함수여야 한다.

  • 리듀서 함수는 이전 상태와, 액션 객체를 파라미터로 받는다.

  • 이전의 상태는 절대로 건드리지 않고, 변화를 일으킨 새로운 상태 객체를 만들어서 반환한다.

  • 똑같은 파라미터로 호출된 리듀서 함수는 언제나 똑같은 결과값을 반환해야 한다.

마무리

이정도면 Redux를 사용해보기 전에 기본적인 개념은 다 익힌 것 같다. 이제 공식 문서를 따라 직접 프로젝트에 사용해봐야겠다.

참고
[벨로퍼트와 함께하는 모던 리액트] 리덕스
Redux(리덕스)란? (상태 관리 라이브러리)

profile
경험은 일어난 무엇이 아니라, 그 일어난 일로 무엇을 하느냐이다.
post-custom-banner

0개의 댓글