React.js

HOC(Higher-Order-Components)를 활용한 사용자 인증 정보 관심사 분리

Dev갱이 2024. 10. 10. 11:50
728x90

현재 사용자의 로그인 정보가 필요할 때

  • 회원 정보를 상태관리 라이브러리를 통해 전역에 담아서 사용하는 경우
  • 회원 정보가 필요 할때마다 api를 요청
  • SSR에서 HOF 고차함수를 활용하여 인증된 사용자를 props로 넘겨주기
  • HOC 고차 컴포넌트를 활용하여 사용자를 체크하고 인증된 사용자의 정보를 가져오는 관심사를 분리
어떻게 효율적인 방법으로 구현할 수 있을지에 대해 고민 했을 때 해당 4가지 방법을 떠올렸다.

1. 전역 상태 관리 라이브러리 사용

  • 장점: 사용하기 편리하며, 어디서든 쉽게 사용자 정보를 접근할 수 있습니다.
  • 단점:
    • 보안적인 문제: 클라이언트 측에서 전역 상태에 민감한 정보(예: 토큰)를 저장하면, XSS 등의 공격에 노출될 수 있습니다.
    • 인증된 사용자 재검사 문제: 한 번 로그인한 이후 로그아웃 전까지 다시 검증하지 않는다면, 사용자의 인증 상태가 만료된 경우(예: 세션 만료), 사용자가 여전히 인증된 것으로 보일 수 있습니다.

2. 필요할 때마다 API 요청

  • 장점: 항상 최신의 사용자 인증 상태를 유지할 수 있습니다.
  • 단점:
    • 코드 중복 가능성: 인증 정보를 사용하는 여러 컴포넌트에서 동일한 API 호출이 반복될 수 있습니다.
    • 성능 문제: 동일한 데이터를 매번 요청하면 서버에 불필요한 부하를 줄 수 있습니다. 이를 해결하려면 API 요청을 캐싱하거나, React Query나 SWR 같은 라이브러리를 사용하는 것이 좋습니다.

3. SSR에서 HOF를 사용하여 사용자 인증 체크

  • 장점: 1번과 2번의 단점을 해소하며, 서버에서 인증을 처리하여 클라이언트에서 불필요한 인증 로직을 줄일 수 있습니다.
  • 단점: props가 깊어지면, 여러 컴포넌트로 props를 전달해야 하는 불편함이 있을 수 있습니다. Context API를 사용하여 이러한 문제를 어느 정도 해결할 수 있지만, 여전히 복잡해질 수 있습니다.

4. HOC 고차 컴포넌트 사용

  • 장점: 가장 효율적이며 유지보수에 유리합니다. 인증이 필요한 컴포넌트를 HOC로 래핑하여 인증 로직을 캡슐화하고, 관심사를 분리하여 코드 중복을 최소화할 수 있습니다. HOC는 특정 컴포넌트에만 인증이 필요할 때 유용하며, 사용자가 접근할 때마다 최신 인증 상태를 확인할 수 있습니다.
  • 단점: 코드 구조에 따라 HOC의 중첩이 많아지면 다소 복잡할 수 있지만, 잘 관리하면 이는 크게 문제가 되지 않을 것입니다.
결론적으로는 컴포넌트레벨에서 HOC 고차 컴포넌트를 사용하여 useQuery의 캐싱을 사용하여 캐싱하여 최소한의 api를 효율적으로 호출하고 HOC로 래핑하여 인증 로직을 캡슐화하고, 관심사를 분리하여 코드 중복을 최소화 할 수 있게 됩니다. 그리고 또한 사용자가 접근 할때마다 최신 인증 상태를 확인 할 수 있습니다.

 

HOC 컴포넌트로 관심사를 마구마구 분리하여 남발 하면 어떻게 될까?

 

  • 디버깅의 어려움: 중첩된 HOC가 많아지면 React 개발자 도구에서 원래 컴포넌트를 파악하기가 어렵습니다.
  • 컴포넌트 간 결합도 증가: 하나의 HOC를 수정하면 의도하지 않게 여러 컴포넌트에 영향을 미칠 수 있습니다.
  • 성능 문제:
    • 중첩된 HOC가 불필요한 리렌더링을 발생시킬 가능성이 높아집니다.
    • 성능 최적화가 어려워지며, 각 HOC에 대해 개별적으로 최적화해야 하기 때문에 복잡해질 수 있습니다.
좋다고 무작정 쓰기에는 특히나 성능 문제와 컴포넌트간의 결합도가 증가하여 유지보수성이 굉장히 떨어지는것이 큰 단점이다.

 

구현

WithAuthClientSideProps.tsx

 

 

 

 

const CreateEvent: FC<CreateEventPropsWithAuth> = ({
	event,
	isGroupEventId,
	authData,
}) => {
	...
};

export default withAuthClientSideProps<CreateEventProps>(CreateEvent);

 

이렇게 사용 하면 된다. 굉장히 코드가 간결해졌다.

 

// 이전 코드
{/* 프로필 [TODO] */}
<Profile
    username={authData.username}
    searchMember={{
        id: '410b7202-660a-4423-a6c3-6377857241cc',
        username: '양광성',
        email: 'rhkdtjd_12@naver.com',
        profileImage: '/images/profile/profile.png',
    }}
/>

// 수정 된 코드
<Profile username={authData.username} searchMember={authData} />

 

그 효과는 엄청났다...
728x90