프리온보딩 프론트엔드 인턴십 1주차, 이전에 진행한 과제를 가지고 Best Practice을 찾기 위해 서로 의견을 나누는 시간을 가졌다. 동일한 내용의 과제였지만, 구현된 코드는 서로 너무나도 다른 것을 보며 ‘코드를 작성할 때 정답은 없다.’ 라는 말을 다시한번 생각하게 되었다.
라우팅과 리다이랙션
진행한 과제에서 내가 맡아서 생각해본 부분은 페이지 라우팅과 리다이랙션이다. 이전에는 과제를 제출하기에 바빠서 이 부분을 크게 신경쓰지 못했지만, 과제를 진행하면서 조금 더 코트의 양을 줄이면서 간소화할 수 있겠다는 생각을 했던 부분이기 때문에 시작하기 전에 기대가 되었다.
라우팅 정보 리스트화
과제 안에서 페이지의 수는 3개(로그인, 회원가입, TODO)였다. 페이지의 수가 작기 때문에, 라우팅 로직의 코드를 하나하나 하드코딩을 해서 구현할 수 있기 때문에 어렵지 않다는 생각을 하였다. 하지만 페이지의 숫자가 많아진다면 코드를 관리하기 어려울 것이라는 생각을 하게 되었고, 코드를 간소화 하는 방법을 찾아보게 되었다.
페이지와 레이어를 리스트 형태로 만들어 각 경로에 맞는 컴포넌트를 팹핑하여, 해당 리스트를 렌더링하는 형태로 코드를 작성하면 보다 코드를 간소화할 수 있을 것 같다는 생각이 들어 이대로 진행해보기로 하였다.
const routerData = [
{
id: 0,
path: '/',
element: <Home />,
},
{
id: 1,
path: '/signin',
element: <Signin />,
},
{
id: 2,
path: '/signup',
element: <Signup />,
},
{
id: 3,
path: '/todo',
element: <Todo />,
},
];
먼저 위 코드를 보면 라우팅에 필요한 정보들을 리스트화였다. 그런 후에 createBrowserRouter
를 사용하여 라우팅 리스트를 렌더링 하였다.
export const routers = createBrowserRouter(
routerData.map(router => {
return {
path: router.path,
element: router.element,
};
})
);
이전에 하나하나 작성한 코드보다 기능적인 변화는 크게 없지만, 라우팅의 정보를 한 눈에 볼 수 있으면서 코드의 구조를 명확하게 알 수 있었다.
라우트 기반 페이지 분할
이전에 각 페이지 컴포넌트 안에서 리다이렉션 조건에 맞게 이동하도록 코드를 작성하였다. 코드를 작성할 당시에 비슷한 기능을 하는 코드가 반복되어 사용되는 것이 불필요하다는 생각이 들었고, 해당 문제를 해결할 방법을 고민해보기로 했다.
리다이렉션 조건
1. 로그인을 진행한 후, 토큰을 발급받은 상태에서 로그인 및 회원가입 페이지에 접근하면 todo 페이지로 이동
2. 토큰이 없는 상태에서 todo 페이지로 접근하면 로그인 페이지로 이동
구현해야하는 조건을 보면, 페이지를 토큰이 필요한 페이지와 토큰이 필요하지 않은 페이지로 구분할 수 있다는 것을 볼 수 있다. 따라서 토큰의 여부에 따라 페이지를 분리하여 각각의 페이지에 맞게 리다이렉션을 구현하면 어떨까 라는 생각을 하게 되었다.
먼저 라우팅 정보에 토큰이 필요한지 여부에 대한 정보를 넣어 작성하였다.
const routerData = [
{
id: 0,
path: '/',
element: <Home />,
withAuth: false,
},
{
id: 1,
path: '/signin',
element: <Signin />,
withAuth: false,
},
{
id: 2,
path: '/signup',
element: <Signup />,
withAuth: false,
},
{
id: 3,
path: '/todo',
element: <Todo />,
withAuth: true,
},
];
다음으로 컴포넌트들을 맵핑할 때, 토큰 여부에 따라 분리하여 토큰이 필요한 페이지에는 리다이렉션을 진행하는 컴포넌트인 GeneralLayout
으로 감싸고, 토큰이 필요하지 않는 페이지는 그냥 반환되도록 하였다.
export const routers = createBrowserRouter(
routerData.map(router => {
if (router.withAuth) {
return {
path: router.path,
element: <GeneralLayout>{router.element}</GeneralLayout>,
};
} else {
return {
path: router.path,
element: router.element,
};
}
})
);
비록 진행하는 과제에서는 토큰이 필요한 페이지가 todo 페이지 하나이기 때문에 위와 같이 코드를 작성해도 크게 차이를 느낄 수 없지만, 페이지의 수가 많으면 많을 수록 반복해서 작성해야하는 코드의 양을 줄일 수 있습니다. (로그인과 회원가입 페이지를 따로 분리하기 어렵다고 판단하여 해당 페이지에서의 리다이렉션은 페이지 컴포넌트 안에서 진행하였다.)
리다이랙션
이전에는 조건문을 사용하여 페이지마다 리다이랙션을 진행하였다. 동일한 기능을 하는 코드를 함수화하여 재사용할 수 있도록 만들면 더 간결하고 깨끗한 코드 작성을 할 수 있다는 생각을 하였고, 리다이랙션 조건에 따라 페이지를 이동하는 기능을 가지고 있는 custom Hook을 만들어 보게 되었다.
interface useAuthRedirectionProps {
path: PATH;
isRedirectionIfAuth: boolean;
}
const useAuthRedirection = ({
path,
isRedirectionIfAuth,
}: useAuthRedirectionProps) => {
const [isAuth, setIsAuth] = useState<boolean>(!!getLocalStorageToken());
const { replaceTo } = useRouter();
useEffect(() => {
if (getLocalStorageToken()) {
setIsAuth(true);
if (isRedirectionIfAuth) {
replaceTo(path);
}
return;
}
setIsAuth(false);
if (!isRedirectionIfAuth) {
replaceTo(path);
}
}, [isRedirectionIfAuth, replaceTo, path]);
return isAuth;
};
export default useAuthRedirection;
useAuthRedirection
함수는 매개변수로 이동해야하는 경로와 리다이렉션이 발생될 때의 조건을 boolean
값으로 받는다. 조건에 맞게 리다이렉션을 진행하고, 토큰의 여부를 boolean
값으로 반환하게 된다.
이전에 토큰이 필요한 페이지를 감쌌던 GeneralLayout
컴포넌트 안에서 리다이렉트처리를 하게 되면, GeneralLayout
컴포넌트의 자식으로 들어가게 되는 컴포넌트들은 useAuthRedirection
함수가 실행되어 조건에 맞게 페이지를 리다이렉션하게 된다.
후기
만들어본 과제를 다시한번 뜯어 보면서 코드리뷰의 필요성과 중요성에 대해 알게되었다. 코드를 다시 들여다보고 개선해야할 점을 찾는 과정 속에서 생각하지 못했던 부분이나 쉽게 놓쳤던 부분에 대해 생각해보는 시간을 갖을 수 있었고, 개선하는 과정에서 해당 부분을 깊게 공부해 볼 수 있었다.
그리고 내가 작성한 코드만 보며 생각하는게 아니라 팀원들의 코드를 함께 보면서, 코드를 더 효율적이고 직관적으로 작성하는 것에 대해 고민해 볼 수 있어서 좋았다.
'개발이야기 > 원티드' 카테고리의 다른 글
[프리온보딩 프론트엔드 인턴십] 선발과제 (0) | 2023.06.28 |
---|