[React] - Redux 파헤치기: 기초 정보
이번 프로젝트에 Redux를 도입하게 된 이유는 크게 두가지 정도가 있는데, 전 프로젝트를 작업할 때 생겼던 렌더링 오류 방지와 코드 간략화 때문에 진행하게 되었다.
Redux라는게 있고, 대충 상태 관리를 위해 있다는 것만 알고 있었지만 개인적으로는 ContentAPI보다 사용 방법도 더 복잡해 보여서 선뜻 손이 가지 않았는데, 구관이 명관이라고 다른 사람들이 쓰는 데엔 이유가 있겠지 싶어서, 또 새로운 걸 공부하고 싶어서 선택했다.
글을 읽기에 앞서, 글은 Redux toolkit을 기반으로 작성되었습니다!
1. Redux란
1.1 Redux 정의
공식 문서에서는 이렇게 정의한다.
Redux는 "액션"이라는 이벤트를 사용하여 애플리케이션 상태를 관리하고 업데이트하기 위한 패턴과 라이브러리입니다.
전체 애플리케이션에서 사용해야 하는 상태에 대한 중앙 저장소 역할을 하며, 규칙은 상태가 예측 가능한 방식으로만 업데이트될 수 있도록 보장합니다.
쉽게 풀어보자면,
상태(state) 변경을 한 곳(store)에서 담당하여 다시 컴포넌트 -> UI 순으로 화면에 보여주는 역할을 한다.
1.2 사용 이유
Redux를 사용하면 무슨 장점이 있을까?
1. 상태 변경이 Store 에서만 이루어지기 때문에 로직이 예측 가능해진다.
모든 상태 변경은 store에서만 처리되어 어디서 변경되는지 추적이 가능해지며 디버깅이 쉬워진다.
2. 단방향으로 데이터가 흐르기 때문에 단순한 구조로 이벤트 루프가 실행된다.
3. 변경 시 모든 컴포넌트의 코드를 수정하는 것이 아니라 코드 관리가 용이해지며 대형 프로젝트의 편의성이 증가한다.
여러 컴포넌트에서 상태가 공유되어도 변경 로직을 한 곳에서 관리할 수 있어 대형 프로젝트의 코드 관리가 용이해진다.
4. 모든 컴포넌트에 중복된 함수를 작성하지 않기 때문에 코드 중복이 줄어든다.
action과 reducer를 통해 상태 변경을 관리하여 각각의 개별 컴포넌트에서 상태 변경 함수를 중복으로 작성하지 않아도 되며 코드 일관성이 좋아진다.
5. state 정보 값을 자식 컴포넌트에 전달할 때 props를 사용하지 않아 Props drilling을 방지할 수 있다.
기존 리액트에서는 부모 컴포넌트에서 자식 컴포넌트, 그 밑의 컴포넌트로 상태를 전달하게 되면 무조건 직계 부모와 자식간의 전달밖에 허용되지 않아 부모->자식->자식의 자식-> 자식의 자식의 자식 등의 프랍스 드릴링이 일어났지만, redux를 사용하게 된다면 필요한 컴포넌트에서 직접적으로 store에서 상태를 가져올 수 있어 프랍스 드릴링을 방지할 수 있다.
2. Redux 구조
2.1 Redux 용어
- Store: 애플리케이션의 전체 상태를 담고 있는 저장소로 상태 변화를 감지한다.
- Selector: store에서 선택한 상태의 특정 정보값을 가져온다.
- Dispatch: 상태를 업데이트 하기 위하여 액션 객체를 store에 전달해준다.
- Reducer: dispatch를 통해 실행된 action의 type을 받아 state의 특정 정보 값을 type에 맞게 상태를 업데이트 해준다.
- Action: 애플리케이션에서 발생한 변경 사항을 설명하는 이벤트
- Type: action에서 실행 될 작업을 설명하는 이름, 어떤 작업을 수행할 지 결정한다.
- payload: 선택적 속성으로, 필요한 데이터를 전달하여 비동기 함수가 성공적으로 실행된 후 반환하는 값이 담긴다.
- Status: 현재 애플리케이션의 상태
- Slice:
- reducer 로직과 액션의 모음으로 한 번에 관리할 수 있게 해주며, reducer를 업데이트 하는 역할을 한다.
- redux의 상태를 세분화하여 여러 개의 상태로 나누어진 것
2.2 Redux 공식 홈페이지의 파일 구조
- /src
- index(main).js: 앱의 시작점
- App.js: 최상위 React 컴포넌트
- /app
- store.js: Redux 스토어 인스턴스를 생성합니다
- /features
- /counter
- Counter.js: 카운터 기능의 UI를 보여주는 React 컴포넌트
- counterSlice.js: 카운터 기능에 대한 Redux 로직
- /counter
공식 홈페이지의 파일 구조를 보면 store와 다른 redux의 기능이 분리 되어 관리된다.
app 폴더 내부에 store 파일을 따로 저장하여 모든 상태 정보를 담고 있다.
feature 폴더 내부에는 상태slice 파일을 작성하여 각각의 상태를 분리한다.
store 파일의 reducer를 통해 각각의 slice 파일 내부에서 상태를 변경할 수 있는데, slice 파일 내부에서는 createSlice를 통해 slice를 생성하며, 특정 기능 (예시에서는 counter라는 컴포넌트와 그의 기능)에 대한 상태와 로직을 관리한다.
2.3 Redux 구조 및 이벤트 루프 과정
편의상, 이미지 제작 시 이벤트 루프를 설명하기 위해 0번을 추가하지 않았지만 화면이 띄워지는 과정은 0번 부터 시작한다.
0. 컴포넌트 내부 Selector를 통해 store에서 상태 정보 값을 가져와 UI에 표시한다.
- UI → Dispatch
- UI에서 발생한 사용자의 입력 혹은 이벤트가 컴포넌트의 dispatch로 전달된다.
- Dispatch → Action
- dispatch를 통해 액션을 실행하며 type과 payload(선택)를 포함하여 상태 변경을 설명한다.
- Action → (type) → Reducer
- action이 reducer로 전달되어 새로운 상태를 만든다.
- Reducer → Status
- 만들어진 새 상태에 따라 status같은 상태를 업데이트한다.
- Status → Selector (5)
- 변경된 상태를 Selector를 통해 컴포넌트에 전달한다.
- Selector (5, 6)
- Selector에서 가져온 상태를 component에 전달, component는 변경된 정보를 토대로 UI를 업데이트, 새롭게 표시한다.
3. 마치며
3.1 Redux 요약
- Redux는 상태 관리를 위하여 사용한다.
- 상태 관리는 전체 상태를 담고 있는 Store에서 이루어진다.
- 컴포넌트에서 selector를 통해 store의 정보를 가져온다.
- 사용자 요구나 이벤트를 dispatch를 통해 store에 전달하여 상태를 변경시킨다.
3.2 개인 소감
개인적으로 store는 은행과 비슷하다는 생각이 든다.
redux는 내가 느끼기에 타입스크립트처럼 느껴졌는데, 배우기 어렵지만 막상 시작하면 재밌고, 상태 관리와 코드를 간략하게 한다는 점에서 가장 맘에 든다.
개인적으로 나의 프로그래밍 가치는 협업하기 쉬운 코드와 누가 봐도 알기 쉬운 코드를 지향하기 때문에 시작이 어려울 뿐, 알고 있는 사람에게는 더욱 쉬운 코드를 작성하기에 좋을 것 같다. 가독성 있는 코드 최고!
늘 느끼지만 공식 문서는 처음에 읽을 땐 잘 모르겠는데, 한번 사용하고 읽으면 이것만큼 잘 쓰여진 글이 없는 것 같다.
.
.
.
개인이 공부하고 작성한 글이라 틀린 정보가 있을 수도 있으며, 알려주시면 수정하겠습니다.