React Context 설정 방법

Prop drilling은 코드를 망가뜨립니다. 필요하지 않은 5개의 컴포넌트 계층을 거쳐 데이터를 전달하게 되기 때문입니다. React Context는 이 문제를 해결해 줍니다. 하지만 대부분의 설정 방식은 새로운 문제를 야기합니다.

context hook에서 "Go to Definition"을 사용하면, 종종 아주 작은 useContext 호출만 있는 파일로 이동하게 됩니다. 실제 로직은 다른 파일에 들어있기 때문입니다. 결국 하루 종일 상태(state) 로직을 찾아 헤매게 됩니다.

더 나은 구조를 통해 이 문제를 해결할 수 있습니다.

다음 패턴을 따르세요:

  • context, public hook, 그리고 state 로직을 하나의 파일에 넣습니다.
  • Provider는 얇은 껍데기(thin shell) 역할만 하도록 유지합니다.
  • lint 규칙을 사용하여 private 로직을 보호합니다.

파일 구조를 다음과 같이 구성하세요:

src/context/ • GameContext.ts (Context, public hook, state 로직) • GameProvider.tsx (얇은 껍데기)

GameContext.ts 내부에 세 가지 부분을 만듭니다:

  1. context 객체.
  2. 컴포넌트에서 사용할 public hook. 이 hook은 context가 null일 경우 에러를 던져야(throw) 합니다. 이를 통해 컴포넌트가 provider 외부에서 사용될 경우 즉시 오류를 발견(fail fast)할 수 있습니다.
  3. 상태 관리를 위한 private hook. 이 hook에 useState 또는 useReducer 호출을 포함합니다.

public hook과 private 로직을 같은 파일에 두면 "Go to Definition"이 완벽하게 작동합니다. 컴포넌트에서 로직으로 즉시 이동할 수 있습니다.

한 가지 위험 요소가 있습니다. Provider에서 사용할 수 있도록 private hook을 export하기 때문에, 동료 개발자가 이를 잘못된 위치에서 호출할 수도 있습니다. 만약 그렇게 되면, 공유된 context를 사용하는 대신 새롭고 격리된 상태를 만들게 됩니다.

이를 방지하기 위해 주석을 사용하는 것은 그만두세요. 대신 ESLint 규칙을 사용하세요.

저는 이 문제를 해결하기 위해 eslint-plugin-restrict-callers를 만들었습니다. 특정 hook을 호출할 수 있는 함수를 정의할 수 있습니다.

예를 들어, GameProvider만이 useGameStateManagement를 호출할 수 있다고 ESLint에 설정할 수 있습니다. 다른 곳에서 호출을 시도하면 명확한 에러 메시지와 함께 빌드가 실패합니다.

워크플로우 요약:

  • context, public hook, private 로직을 하나의 파일로 그룹화합니다.
  • Provider는 hook의 결과값을 provider value로 전달하는 용도로만 사용합니다.
  • context가 누락된 경우 public hook에서 에러를 던집니다.
  • ESLint를 사용하여 public hook과 private hook 사이의 경계를 강제합니다.

출처: https://dev.to/jareddlewis/how-to-set-up-react-context-2c9h