리액트의 대표적인 상태 관리 라이브러리인 redux 와 조금 더 redux 를 편하게 이용하기 위한
redux-toolkit 에 대하여 알아보겠습니다😀
( 미들웨어로 사용되는 리덕스 청크, 사가 등은 제외하고 기본적인 redux 에 대한 공부 입니다! )
먼저 Redux 란 ❓
사실 redux 는 리액트를 위해 만들어진 것이 아닙니다!
즉, redux 는 react 와 전혀 상관없는 라이브러리 입니다.
redux 는 자바스크립트 앱을 위한 예측 가능한 상태 컨테이너 - 출처 : https://ko.redux.js.org/
따라서 react 에서 redux 를 사용하려면 redux 를 설치하고 react-redux 를 따로 설치해야 합니다.
( 처음에 이 부분 때문에 왜 설치 해도 안될까..? 라고 생각 하실 수 있습니다. )
그렇다면 react-redux 는 ❓
React는 SPA를 만들기 위해 사용 합니다. React는 자체적으로 state(와 props)를 관리할 수 있지만 컴포넌트가 많아지고 깊어지면 state의 값을 관리하기가 힘듭니다. 따라서, redux는 state를 편하게 관리하기 위한 목적으로 사용 됩니다.
아래는 redux-react 사이트에 있는 설명 입니다.
Redux 자체는 React, Angular, Vue, Ember 및 vanilla JS를 포함한 모든 UI 레이어 또는 프레임워크와 함께 사용할 수 있는 독립형 라이브러리 입니다. Redux와 React는 일반적으로 함께 사용되지만 서로 독립적입니다. 모든 종류의 UI 프레임 워크와 함께 Redux를 사용하는 경우 일반적으로 UI 코드에서 'UI 바인딩' 라이브러리를 사용하여 Redux를 UI 프레임 워크와 연결합니다.
React Redux는 React용 공식 Redux UI 바인딩 라이브러리입니다.
즉, Redux와 React를 함께 사용하는 경우 React Redux를 사용하여 라이브러리를 바인딩 해야 합니다. ( 연결 이라고 보면 됩니다 )
Redux 는 중요한 3가지 원칙을 가지고 있습니다.
스토어는 글로벌 상에서 하나만 존재해야한다. (= 하나의 스토어에 모든 상태가 관리되어야 한다)
상태는 읽기 전용으로, 액션 객체에 전달해야지만 변화할 수 있다.
변화는 순수함수로 작성해야한다.
순수함수 : 외부의 개입 없이 동일한 인풋값에 따라 항상 동일한 결과를 내보내느 함수
리듀서 : 이전 상태의 액션을 받아 다음 상태를 반환하는 순수 함수. 이전 상태값을 변경하는 것이 아닌 새로운 상태값을 반환 합니다.
위 3가지의 원칙을 지키면 자연스럽게 사용이 가능 합니다.
Redux 용어 설명
1. Store
스토어는 컴포넌트의 상태를 관리하는 저장소. 하나의 프로젝트는 하나의 스토어만 가질 수 있습니다.
2. Action
스토어의 상태를 변경하기 위해서는, 액션을 생성해야 합니다. 액션은 객체이며, 반드시 type을 가져야 합니다. 액션 객체는 액션 생성함수에 의해서 만들어 집니다.
3. Reducer
리듀서는 현재 상태와 액션 객체를 받아 새로운 상태를 리턴하는 함수
4. Dispatch
디스패치는 스토어의 내장 함수 중 하나이며, 액션 객체를 넘겨줘 상태를 업데이트 시켜주는 역할을 합니다.
기존 useReducer 에서 사용되는 단어의 정의와 비슷합니다 ➡️ [React] - useReducer
먼저 참고하시면 좋을 것 같습니다!!
Redux 흐름
UI가 처음 렌더링될 때, UI 컴포넌트는 리덕스 스토어의 상태에 접근하여 해당 상태를 렌더링
이후 UI에서 상태가 변경되면, 앱은 디스패치를 실행해 액션 발생
새로운 액션을 받은 스토어는 리듀서를 실행하고 리듀서를 통해 나온 값을 새로운 상태로 저장
UI는 상태 업데이트로 변경된 데이터를 새롭게 렌더링
Redux 를 사용하려면
하지만 redux 를 사용하기 위해 스토어를 생성하면 아래와 같이 표시 됩니다.
리덕스에서 리덕스 툴킷이라는 것을 만든 후에 그걸 사용을 권장하게 만들어놨습니다. 기존 리덕스 만 사용하려면 복잡하고 불편한데 툴킷을 사용하면 더 편하게 리덕스를 사용 하실 수 있습니다. 그렇다면 리덕스 툴킷에 대해 알아보도록 하겠습니다.
Redux-toolkit ❓
먼저 명령어를 사용해서 설치 합니다.
( 이전에 redux 와 react-redux 를 설치하는 것은 동일 합니다! )
지금부터는 예시를 통해 직접 살펴보겠습니다.
먼저 Redux 를 사용하지 않은 카운터 예제
plus, minus 따라 컴포넌트 안에서 state 의 값이 달라질 것 입니다.
하지만 useState 를 사용한 state 값은 선언한 컴포넌트 내부에서 사용하게 되며, 해당 컴포넌트 밖에서 사용하고 싶은 경우는 props 로 값을 전달해줘야 합니다.
하지만.. ❗️
처음에 말했다시피 props 로 전달하게 되면 컴포넌트 깊이가 깊어질수록 추적하기 어렵고 props drilling 이 발생할 수 있습니다
또한 props 로 인한 상태 변경이 한 번 일어났을 뿐인데, 데이터를 변경하기 위한 예상치 못한 상태 변경이 일어날 가능성이 커집니다.
우리는 이러한 문제를 예방하고자 상태관리 라이브러리인 redux 를 배웠고, redux 에 알맞게 코드를 바꿔보겠습니다.
1. store 생성
위에서 언급했던 3가지 원칙 중 하나인 '스토어는 글로벌 상에서 하나만 존재해야한다'
라는 말을 기억하시나요 ? 먼저 디렉토리 구조를 보겠습니다.
원칙을 따라 앞으로 store.js 에서 모든 상태 변화를 관리하도록 하겠습니다. 해당 파일의 구조는
1. 먼저 store.js 파일 안에 configureStore() 로 스토어를 만듭니다.
2. 아직 소개하지는 않았지만 createSlice() ➡️ counterSlice 를 store 안에 import 합니다.
3. combineReducers 는 각 reducer 를 호출하여 초기 상태를 검색 합니다.
( 없으면 나중에 useSelector 로 값을 못 불러올수 있습니다 )
2. 그렇다면 createSlice() 는 무엇인가 ❓
액션타입, 액션 생성 함수, 해당 액션의 리듀서 등을 하나의 파일로 통합할 수 있게 한다.
기존 리덕스와 비교하여 참고하면 좋은 글 : https://jwdevv.tistory.com/36
기존 Redux 의 리듀서 로직과 액션을 단순화하는데 도움이 되는 API 라고 볼 수 있습니다.
아래 코드는 store 에 import 했던 counterSlice 입니다.
name : useSelector 할 때 값을 가져오는 장소의 이름
initialState : state 의 초기값, 즉 처음 상태를 정의 합니다.
reducers : 해당 state를 변화시키는 action 을 지정 합니다.
actions : dispatch 를 통해 상태를 변화 시킬 수 있는 함수
❗️ 사실 실무에서 바로 사용하는 위주로 배워서 이론이 많이 빈약 할 수 있습니다.. 언제나 피드백은 환영입니다..
3. store 연동
provider 는 react-redux 에서 리액트 앱이 스토어를 연동 할 수 있게 해주는 컴포넌트 입니다.
아래와 같이 감싸주고 사용합니다.
4. useSelector, useDispatch 로 상태에 접근해보자 ❗️
마지막으로, 해당 값을 꺼내오고 변화시키는 방법 입니다.
useSelector() : 스토어에서 현재 상태 값을 가져온다.
useDispatch() 를 통해 변경되는 값을 스토어로 전달한다.
직접 확인해봅시다❗️
➡️ 리덕스는 리액트를 배우면서 가장 러닝 커브가 높다고 합니다.. 실제로 해보니까 저도 가장 어려웠고 아직도 어렵습니다.. 그래도 이번 글을 통해 조금이나마 이해하셨으면 좋겠고, 아쉬운 부분은 피드백을 해주시면 감사하겠습니다 🥹
참고
https://velog.io/@youthfulhps/What-is-Redux-and-why-use-it
https://ko.redux.js.org/introduction/getting-started/