현재 프로젝트 기간이기 때문에 자주 글을 쓸 수 없다(물론 노션에다가는 매일 기록하고 있다.)
[ 로그인 구현을 위해 한 삽질들 ]
이슈
Next.js는 서버 사이드에서 실행된다.
기존 리액트에서 사용하던 방식대로 사용하면 안된다.
근데 기존 리액트에서 쓰는 방식 처럼, Next.js는 처음에 서버 사이드에서 실행된 다음 클라이언트에서 실행되기 때문이다.
[ 해결 방법은? ]
리액트스럽게 해결한다.
리액트스럽게 해결한다는 것은 무조건 client side에서 해당 코드들이 실행되게 만들면 된다. 무조건 client side에서 해당 코드들을 실행할 수 있는 방법은 useEffect hook으로 감싸면 된다.
그런데, 여기서 문제가 끝이 아니다. 처음 유저 상태를 전역으로 가져와야 하고, 만약 토큰이 만료되었을 때 사용자의 상태를 지워야할 경우 interceptor에서 ContextApi에 선언된 상태에 접근할 수 있어야 한다. 이 때 두 가지 방법이 있다.
나는 두 번째 방식을 선택했다. interceptor의 특성 상 필요한 부분에만 사용되는 것이 아닌, 전역적으로 실행되어야 한다고 생각했다. 프로바이더를 _app.tsx에서 상위 컴포넌트들을 감싸면 initial load일 때 무조건 실행될 것이라고 판단했고, 실제로 프로바이더로 감싸보았더니 interceptor가 잘 동작함을 확인할 수 있었다. 또한 InterceptorProvider에서 AuthContext 내부 데이터들에 대해 접근이 가능함을 확인할 수 있었다.
주의: 감싸는 순서가 중요하다. 가장 처음에는 AuthContextProvider가 되어야 한다.
storage 관련 이슈 해결하기
이것은 온라인으로 찾아보니까 생각보다 간단했다. 마찬가지로 리액트스럽게 useEffect hook을 이용하여 hook 내부에서 사용하는 방식이 있었는데, 이 방식은 Provider와는 반대로 굳이 hook 내부에 선언할 필요는 없겠다고 생각해서, 또 좀 더 쉬운 방식이 있길래 해당 방식은 사용하지 않았다.
클래스로 선언하여 해결하기
클래스로 선언하여 if (typeof window)를 통해 필터링해준다면, 해당 코드는 서버, 클라이언트 모두 실행됨에도 불구하고 서버에서 에러를 내지 않게 된다. 다만, if (typeof window === 'undefined')
코드가 계속해서 중복되므로, 이를 해결할만한 좋은 아이디어가 있는지 찾아볼 필요는 있겠다.
class LocalStorage {
static setItem<T = unknown>(key: string, value: T) {
if (typeof window !== 'undefined') {
localStorage.setItem(key, JSON.stringify(value));
}
}
static getItem<T = unknown>(key: string, defaultValue: T) {
if (typeof window !== 'undefined') {
const value = localStorage.getItem(key);
if (!value || value === 'undefined') return defaultValue;
return JSON.parse(value) as T;
}
return null;
}
static removeItem(key: string) {
if (typeof window !== 'undefined') {
localStorage.removeItem(key);
}
}
}
export default LocalStorage;
아직 과제가 남아있다
next.js 특성상 항상 홈페이지로 진입하는 것이 아닌 여러 페이지로 진입할 수 있기 때문에, initial load일 때 사용자 프로필 정보를 불러와야 한다. 따라서 이 역시 프로바이더 형식으로 감싼 뒤 AuthContext 정보에 접근하여 값을 수정하는 방식을 사용해 보려고 한다.