Context API가 Redux를 대체할 수 있을까요?
React 16.3 버전에서 정식으로 Context API가 발표되었습니다. Props를 직접 전달하는 것과 달리, Context는 중간의 컴포넌트를 건너뛰고 원하는 컴포넌트로 바로 상태를 전달할 수 있어서 예전부터 React 라이브러리 개발자들 사이에서 요긴하게 쓰였습니다. 이제 새 API를 통해 앱 개발에서도 안심하고(그리고 편리하게) Context 기능을 사용할 수 있게 되었습니다.
새 API는 <Provider />
와 <Consumer />
를 통해 선언적으로 Context를 사용할 수 있도록 설계되어 있습니다. 전역 상태를 <Provider />
에 제공하면 트리 내의 어디에서나 <Consumer />
를 통해 가져올 수 있습니다. 공식 문서의 예제를 가져와 보겠습니다.
Redux에 익숙하신 분들이라면 <ThemeContext.Provider />
가 react-redux의 <Provider />
에, withTheme()
가 connect()
에 대응한다는 사실을 눈치채셨을 겁니다. 같은 코드를 Redux로 짜면 이렇게 됩니다.
이쯤 되면 ‘Context API가 Redux를 대체할 수 있지 않을까?' 하는 의문을 품게 됩니다. Redux가 출시되었을 당시 공식 문서를 번역했을 정도로 Redux 팬인 저에게도 이런 질문을 하는 분들이 많았고요.
여기에 답하기 위해 먼저 답해야 하는 질문이 바로 '왜 Redux를 쓰는가?' 입니다. 2015년 당시에 제가 Redux를 썼던 이유는 'Flux 아키텍처를 위한 가장 훌륭한 상태 관리 구현체가 Redux이기 때문에' 였습니다. Facebook에서 Flux 아키텍처와 함께 공개한 dispatcher 구현체를 직접 뜯어서 쓰던 저에게 Redux가 얼마나 예뻐보였을까요.
하지만 Redux는 단순히 전역 상태 관리를 위해서만 사용하기에는 너무 번잡한 도구입니다. 배우기가 까다로워서 React에 입문하는 동료들을 좌절시키기도 하고, 태생적인 제약조건들 때문에 앱을 짜면서도 번거로운 부분이 한둘이 아닙니다. 그럼에도 아래와 같은 장점들 때문에 Redux가 강력한 것이죠.
로컬 스토리지에 상태를 영속적으로 저장하고 시작할 때 다시 불러오는 데 특히 뛰어납니다.
상태를 서버에서 미리 채워서 HTML에 담아 클라이언트로 보내고 앱을 시작할 때 다시 불러오는데 특히 뛰어납니다.
사용자의 액션을 직렬화해서 상태와 함께 자동으로 버그 리포트에 첨부할 수 있습니다. 개발자들은 이를 통해 에러를 재현할 수 있습니다.
액션 객체를 네트워크를 통해 보내면 코드를 크게 바꾸지 않고도 협업 환경을 구현할 수 있습니다.
실행취소 내역의 관리나 낙관적인 변경(optimistic mutations)을 코드를 크게 바꾸지 않고도 구현할 수 있습니다.
개발할 때 상태 내역 사이를 오가고 액션 내역에서 현재 상태를 다시 계산하는 일을 TDD 스타일로 할 수 있습니다.
개발자 도구에게 완전한 조사와 제어를 가능하게 해서 개발자들이 자신의 앱을 위한 도구를 직접 만들 수 있게 해 줍니다.
비즈니스 로직 대부분을 재사용하면서 UI를 변경할 수 있게 해 줍니다.
이러한 장점들을 활용할 필요가 없다면, 전역 상태를 관리하기 위해 Context API를 활용하는 방법을 추천합니다. 필요하다면 Redux의 장점을 일부 빌려올 수도 있습니다. 리듀서를 따로 분리해내서 순수함수의 장점을 활용할 수도 있고, combineReducers
와 유사하게 여러 Context를 동시에 사용할 수 있는 HOC를 만들어 쓰셔도 됩니다.
저도 이미 사내 프로젝트 하나를 Redux에서 Context API로 완전히 전환했습니다. 코드 면적이 많이 줄었고 동료들이 이해하기에도 더 쉬워졌습니다. 앞으로도 위에서 나열한 것과 같이 특별한 이유가 아니면 Redux를 다시 꺼내 들지는 않을 것 같습니다. 하지만 Redux가 쓸모없어졌다고 생각하지는 않습니다.
닭 잡는데 소 잡는 칼을 쓰지 않게 되었을 뿐입니다.