리액트를 배운지도 벌써 한 달이 됐다. 그동안 프로젝트 2개를 진행했는데 각 프로젝트를 하면서 상태 관리는 오직 useState로만 했었다.
리액트 배운지 일주일도 안 됐던 시점에 무려 아토믹 디자인 패턴을 도입했던 첫 번째 프로젝트에서 useState를 사용해서 상태를 만들고 Props로 열심히 자식 컴포넌트들에게 상태를 전달하던 중.. '상태 관리를 좀 더 편하게 할 수는 없을까?'라는 생각이 들었다.
해당 프로젝트에서 Drag & Drop 기능을 가진 To do List를 구현했는데 Button, Label 등의 최소 컴포넌트 단위로 나눈 Atoms에서 가장 큰 단위인 Page까지 상태를 주고 받으려면 최대 5단계에 걸쳐 상태를 내려 보냈어야 했다..정말.. 나중에는 내가 이 상태를 어디서 내려보냈는지까지 헷갈릴 지경이었다.🤦♀️
이렇게 React에서 상태를 전달할 때 A에서 C까지 상태를 전달해야 할 때 B를 반드시 거쳐야 하는 구조를 가져서 마치 props를 부모에서 자식 컴포넌트로 내리 꽂듯이 전달한다고 해서 Props Drilling 이라 한다고 한다. (진짜 드릴 그 자체였음.. Page 부터 Atom까지 드릴 가능..🔩)
아무래도 상태 관리에 있어서 이렇게 컴포넌트간의 상하 의존성이 크면 계층 구조로 된 컴포넌트 들을 분리하기 어려워지고,
props가 변경 될 때마다 상태가 관리되고 있는 전역 코드를 수정 해야 하는 번거로움이 있다.
그렇게 두 번의 프로젝트를 통해 상태 관리가 중요하다. 어렵다는 것을 깨닫고 있었는데! 마침 크롱이 useReducer와 Context API 개념을 설명해주셔서 개념 정리를 해보고, 프로젝트에서 적용해보며 두 개념의 장점을 조금씩 깨우쳐보려 한다.
useReducer는 useState 보다 더 복잡한 상황에 다향한 상태를 다른 값으로 업데이트해 주고 싶을 때 사용하는 Hook이다. Reducer는 현재 상태와 업데이트를 위해 필요한 정보를 담은 객체인 action 값을 전달 받아서 action에 맞는 방법으로 업데이트 된 새로운 상태를 반환하는 함수이다. 그래서 useState의 State를 변경하는 함수는 넘겨 준 값을 그대로 다음 State로 사용하는 것과 다르게 useReducer의 State를 변경하는 함수는 reducer를 거치면서 추가적으로 가공한 State로 사용할 수 있다.
function reducer(state, action) {
return { //업데이트한 새로운 상태 반환
};
Context API는 앞서 말한 Props Drilling를 Redux없이 해결할 수 있도록 하는 React API이다. Context API는 프로젝트 안에서 사용 할 수 있는 여러 값(현재 로그인한 유저, 테마, 선호하는 언어 등)을 전역적으로 관리 하기 때문에 값을 props로 일일히 내려주지 않아도 값을 사용할 하위 컴포넌트에서 해당 값을 불러서 사용할 수 있다. 다만 상태가 변경될 때마다 Provider로 감싸진 모든 하위 컴포넌트가 리 렌더링 되니 적절한 위치에서 Context를 정의해주는 것이 중요하다.
Context API에는 Provider, Consumer 개념이 있는데 Provider는 context를 구독하는 하는 컴포넌트들에게 context 변화를 알려주고 Consumer는 Provider가 전달한 값을 사용한다.
참고