[Step2.1] hippo: Context API 적용하기 - #3
Conversation
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Free Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Walkthrough문서가 Context API 전역 상태관리 과제로 갱신되고, ChangesContext API 전환과 문서 갱신
Sequence Diagram(s)sequenceDiagram
participant User
participant AddRestaurantModal
participant RestaurantsContext
User->>AddRestaurantModal: 폼 제출
AddRestaurantModal->>RestaurantsContext: addRestaurant({ category, name, description })
RestaurantsContext-->>AddRestaurantModal: 추가 완료
AddRestaurantModal->>AddRestaurantModal: onClose()
Estimated Review Effort🎯 3 (Moderate) | ⏱️ ~20 minutes Note 🎁 Summarized by CodeRabbit FreeYour organization is on the Free plan. CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please upgrade your subscription to CodeRabbit Pro by visiting https://app.coderabbit.ai/login. Comment |
|
@coderabbitai review |
✅ Action performedReview finished.
|
| ### React 18 vs React 19 Provider 문법 차이 | ||
|
|
||
| 기존 styled-component를 상속해서 스타일을 추가할 수 있다. | ||
| React 19부터는 Context 객체 자체를 Provider로 사용할 수 있다. 공식문서가 React 19 기준으로 업데이트되었으므로 버전 확인이 필요하다. |
There was a problem hiding this comment.
[배움]
리액트 버전에 따른 문법 차이가 있는 줄 몰랐는데 덕분에 알게되었습니다. Provider를 사용할 때 버전 확인을 할 필요가 있겠네요!
| const [category, setCategory] = useState(""); | ||
| const [name, setName] = useState(""); | ||
| const [description, setDescription] = useState(""); | ||
| const { addRestaurant } = useContext(RestaurantsContext); |
There was a problem hiding this comment.
[제안]
createContext(null)로 초기화해서 Provider 없이 useContext를 호출하면 null을 반환하도록 설정한 건 좋은 것 같아요. 근데 지금은 그냥 TypeError 기본 에러가 뜨는데, 메시지만 봐서는 Provider가 빠진 게 원인인지 바로 알기 어렵다고 생각해요!
export function useRestaurantsContext() {
const context = useContext(RestaurantsContext);
if (context === null) throw new Error("RestaurantsProvider 내부에서만 사용할 수 있습니다.");
return context;
}이렇게 커스텀 훅으로 감싸면 의도를 담은 에러를 던질 수 있어서 원인 파악이 더 쉬워질 것 같아요. 적용해보는 건 어떨까요?
There was a problem hiding this comment.
네 리팩토링에 적용해보도록 하겠습니다
| selectedCategory, | ||
| onRestaurantClick, | ||
| }) { | ||
| const { restaurants, isLoading, error } = useContext(RestaurantsContext); |
There was a problem hiding this comment.
[배움]
isLoading, error를 App이 아닌 RestaurantList에서 처리한 게 처음엔 의아했는데, 읽다 보니 데이터를 쓰는 컴포넌트가 그 데이터의 상태도 함께 처리한다는 판단인 것 같아서 좋은 방식인 것 같아요. restaurants를 실제로 보여주는 건 RestaurantList니까, 서버가 실패했을 때 어떻게 표시할지도 RestaurantList가 결정하는 게 응집도 측면에서 맞는 것 같아요. 이게 나중에 TanStack Query에서 const { data, isLoading, error } = useQuery()로 데이터와 상태를 한 곳에서 처리하는 패턴이랑 같은 방향이라는 것도 알게 되어서 좋은 공부가 되었습니다!
개인 목표 달성 여부
createContext,Provider,useContext세 가지 개념의 역할을 명확히 이해하고 직접 구현한다.리뷰어에게
Context API를 사용한 이유와 trade-off
왜 Context API를 선택했는가
기존 구조에서
restaurants,addRestaurant,isLoading,error는 모두App이useRestaurants훅을 직접 호출해서 관리하고 있었습니다. 이 데이터들을 필요로 하는 컴포넌트가RestaurantList,AddRestaurantModal로 분산되어 있어 App이 중간 전달자 역할만 하는 구조였습니다.특히
addRestaurant는useRestaurants→App→handleRestaurantSubmit→AddRestaurantModal로 이어지는 경로를 거쳐야 했는데,App은 실질적인 처리 없이 전달만 하고 있었습니다. 이처럼 여러 컴포넌트에서 공유되는 데이터 도메인(서버 데이터 + 관련 액션) 을 Context로 분리하는 것이 적합하다고 판단했습니다.trade-off
value가 변경되면 해당 Context를 구독하는 모든 컴포넌트가 리렌더링된다. 현재는 restaurants, addRestaurant, isLoading, error를 하나의 객체로 묶어 전달하므로, 어느 하나만 바뀌어도 모든 구독 컴포넌트가 리렌더링될 수 있다.selectedCategory같은 UI 상태는 App이 계속 관리한다. 특정 화면의 인터랙션 상태는 Context보다 로컬 state가 더 자연스럽다고 판단했다.Context API와 컴포넌트 관계 도식