1차 프로젝트에서의 장바구니 기능을 리팩토링을 진행하였다.
이전에는 상품 상세 페이지와 상품 리스트 페이지에서 상품을 장바구니에 담으면 백앤드 측으로 POST 요청을 보내 장바구니에 담은 항목의 정보를 보내 사용자의 장바구니 항목을 업데이트하고 장바구니 페이지에서는 header에 사용자의 토큰을 담은 GET 요청을 통해 사용자의 장바구니 리스트 정보에 접근하여 담겨있는 아이템들을 보여주는 식이었다.
이번 리펙토링에서는 백앤드가 없이 프론트앤드에서만 리펙토링을 진행하게 되어서 따로 백앤드와의 통신 없이 Mockdata를 통해 redux로 상태 관리를 해보았다.
지난번 프로젝트에서 redux를 적용하여 전역 상태관리를 해보았기에 크게 어렵게 느껴지지는 않았다.
하지만 redux를 사용하면서 사용하기 위한 사전 코드가 너무 많은 거 같다는 느낌을 받았다.
그래서 상태관리를 전역으로 관리하는 방법을 찾다 보니 context API라는 리액트 내에서 제공하는 방법을 찾게 되었다.
🌐 Context API
context API는 리액트에서 제공하는 전역상태관리 도구로 리액트에서만 사용할 수 있다.
context를 생성하여 상태값을 선언하고(createContext ),
자식 컴포넌트들에게 전달한 후에(context이름.Provider 태그)
자식 컴포넌트에서 해당 상태값을 사용할 수 있다.(useContext 혹은 context이름.Consumer 태그)
context API를 사용한 예시를 만들어 보았다.
컴포넌트 구조
App.js (최상단 컴포넌트)
ChangeColorForm.js
AppChild.js
AppGrandChild.js
Context.js
contextAPI 사용시 함수형 컴포넌트를 사용한다면 useContext를 통해 쉽게 context의 상태 값에 접근, 수정이 가능하지만,
클래스형 컴포넌트 사용시에는 context의 상태 값을 사용하는 컴포넌트를 사용하고자 하는 context명.Consumer 컴포넌트로 wrapping 해주어야 한다.
그리고 render 밖에서 상태값에 접근할 경우에는 static 타입의 contextType 변수를 사용해 주는데 이 경우 오직 하나의 context만 구독이 가능하다는 단점이 있다.
여러 개의 context를 구독하기 위해서는 render내에서 Consumer 컴포넌트를 중첩하여 사용해 주어야 한다.
contextType
https://ko.reactjs.org/docs/context.html#classcontexttype
여러 context 구독
https://ko.reactjs.org/docs/context.html#consuming-multiple-contexts
⚛️ Redux
리덕스는 전역 상태 관리를 위한 라이브러리로 리액트뿐만 아니라 Angular, Vue와 Vanilla JS에서도 사용할 수 있다.
리덕스 공식문서에서는 자바스크립트 앱을 위한 예측 가능한 상태 컨테이너라고 명시하고 있다.
리덕스를 사용하기 위해서는 세 가지 개념이 필요하다.
- Store
- Reducer
- Action
Store는 하나의 어플리케이션에 하나만 존재하며, 애플리케이션의 모든 상태 값을 관리한다.
createStore(reducer명)을 통해 생성되고, 최상단 컴포넌트를 Provider 컴포넌트로 wrapping하여 하위 컴포넌트에서 store의 상태 값에 접근할 수 있게 된다.
action은 type속성 을 지닌 자바스크립트 객체로 action Creator(action 생성 함수)를 통해 반환된다.
reducer를 통해 지정된 type값에 따라 스토어를 업데이트하게 된다.
reducer는 초기 상태값과 action을 인자로 받아 action의 type에 따라 store를 업데이트시켜주는 자바스크립트 함수이다.
자세한 설명은 따로 리덕스를 정리한 글에서 설명하려고 한다.
위에서 context API를 사용한 예시를 redux를 사용해 똑같이 구현해 보았다.
컴포넌트 구조
index.js (react DOM에서 render 되는 최상단 컴포넌트)
App.js
ChangeColorForm.js
AppChild.js
AppGrandChild.js
Store/action.js
Store/reducer.js
예시 화면 결과는 위와 같으니 생략!
📌 Context API와 Redux의 차이 📌
리덕스가 context API를 사용하여 만든 라이브러리인 만큼 둘은 전역 상태 관리를 가능하게 해 준다는 점에서 닮아있다.
나는 이 둘의 차이점을 크게 세 가지로 나눠 보았다.
- 성능 최적화
- 추가 기능 사용 가능의 유무
- 테스트 코드 작성의 용이
성능적인 면에서 context API는 리덕스와 같이 성능 최적화가 이루어지지 않기 때문에 컴포넌트에서 context의 특정값에 의존하고 있어도 context내의 다른 값이 변경되게 되면 리렌더링을 하게 된다.
이러한 이유 때문에 간단한 애플리케이션에서는 크게 차이가 나지 않지만, 다양한 상태 값이 필요한 애플리케이션의 경우
context를 세세하게 나눠주어야 하고 이러한 점은 관리의 복잡성을 높이기 때문에 high-frequency 어플리케이션의 경우 context API 사용 시 성능상의 이슈가 생길 수 있다.
미들웨어와 추가 라이브러리 사용이 가능하다는 점도 여러 가지의 전역 상태 관리 라이브러리 중 리덕스가 가장 많이 사용되고 강력한 이유이다.
API 요청에는 이제 SWR과 react-query를 주로 사용한다고 하지만 아직까지 리덕스의 미들웨어(redux-saga, redux-thunk 등)가 필요한 부분들이 있기 때문이다.(서버사이드 렌더링 등)
추가적으로 redux-devtools를 통해 store의 상태를 조회하기 용이한 부분도 큰 장점이다.
리덕스는 리액트 밖에서 동작하기 때문에 테스트 주도 개발(TDD) 스타일을 적용하기 쉽다는 점도 리덕스가 가지고 있는 장점이다.
전역 상태 관리만을 사용하기 위해서는 context API와 redux 외에도 여러 가지 방법이 존재한다.
그러므로 자신이 개발하는 애플리케이션의 사이즈와 기능에 맞는 방법을 찾아 선택하는 것이 좋다고 생각한다.
이번에 context API와 redux의 차이점을 알아보던 중 RIDI의 테크 블로그에서 많은 도움을 받은 글이 있어서 공유하려고 한다.
https://ridicorp.com/story/how-to-use-redux-in-ridi/
'개발 > React' 카테고리의 다른 글
TIL #19 (useState, useEffect) (0) | 2021.04.03 |
---|---|
TIL #15 조건부 렌더링 (0) | 2021.03.20 |
TIL #14 동적라우팅 (0) | 2021.03.19 |
TIL #13 합성이벤트, key Prop (0) | 2021.03.10 |
TIL #11 state & props (0) | 2021.03.05 |