Written by
Nostrss
on
on
[리팩토링] 헤더 메뉴들의 onClick 함수 통합
팀 프로젝트 반응형 작업이 어느정도 되어서 진짜 코드 리팩토링을 해보고 싶다는 생각이 들었다. 그래서 가장 먼저 헤더의 메뉴들마다 바인딩 되어 있는 onClick 함수들을 살펴보았다.
변경 전 Container
- 헤더의 메뉴들마다 각각 onClick 함수가 바인딩 되어 있고 각 메뉴 클릭 시 페이지 이동만 해주는 동일한 기능을 하고 있다.
- 그래서 함수를 하나로 만들어서 클릭한 메뉴의 id값에 딸라 페이지를 이동하도록 변경할 예정이다.
- 이렇게하면 Presenter로 내려주는 props의 개수도 좀 줄 줄어들 것 같다.
import { useRouter } from 'next/router';
import { useRecoilState } from 'recoil';
import { accessTokenState, userInfoState } from '../../../../commons/store';
import { useMutation, useQuery } from '@apollo/client';
import { FETCH_USER_LOGGED_IN, LOG_OUT } from '../../queries';
import React, { useEffect, useState } from 'react';
import LayoutHeaderUI from './header.presenter';
export default function HeaderContainer() {
const router = useRouter();
const [isToken, setIsToken] = useRecoilState(accessTokenState);
const [userInfo, setUserInfo] = useRecoilState(userInfoState);
const { data } = useQuery(FETCH_USER_LOGGED_IN);
const [userLogOut] = useMutation(LOG_OUT);
// 채팅방에서 헤더 비노출 처리를 위한 코드
const HIDDEN_HEADER = ['/chat/[chatInfo]'];
const isHiddenHeader = HIDDEN_HEADER.includes(router.pathname);
const [currentPage, setCurrentPage] = useState({
garden: false,
community: false,
chat: false,
charge: false,
profile: false,
});
useEffect(() => {
setUserInfo(data?.fetchUser);
setCurrentPage({
garden: false,
community: false,
chat: false,
charge: false,
profile: false,
[router.asPath.split('/')[1]]: true,
});
}, [data, router]);
const onClickLogo = () => {
router.push('/garden');
};
const onClickChat = () => {
router.push('/chat');
};
const onClickGarden = () => {
router.push('/garden');
};
const onClickCommunity = () => {
router.push('/community');
};
const onClickSignIn = () => {
router.push('/signin');
};
const onClickSignUp = () => {
router.push('/signup');
};
const onClickCharge = () => {
if (!isToken) {
alert('Please Login');
router.push('/signin');
} else router.push('/charge');
};
const onClickLogOut = async () => {
try {
await userLogOut();
setIsToken('');
router.push('/garden');
} catch (error) {
if (error instanceof Error) alert(error.message);
}
};
const onClickMoveMypage = () => {
if (!isToken) {
alert('Please Login');
router.push('/signin');
} else {
router.push(`/profile/${userInfo.id}`);
}
};
return (
<LayoutHeaderUI
isHiddenHeader={isHiddenHeader}
onClickLogo={onClickLogo}
onClickGarden={onClickGarden}
onClickCommunity={onClickCommunity}
onClickChat={onClickChat}
onClickCharge={onClickCharge}
onClickMoveMypage={onClickMoveMypage}
isToken={isToken}
data={data}
onClickLogOut={onClickLogOut}
onClickSignUp={onClickSignUp}
onClickSignIn={onClickSignIn}
currentPage={currentPage}
/>
);
}
변경 후 Container
import { useRouter } from 'next/router';
import { useRecoilState } from 'recoil';
import { accessTokenState, userInfoState } from '../../../../commons/store';
import { useMutation, useQuery } from '@apollo/client';
import { FETCH_USER_LOGGED_IN, LOG_OUT } from '../../queries';
import React, { useEffect, useState } from 'react';
import LayoutHeaderUI from './header.presenter';
export default function HeaderContainer() {
const router = useRouter();
const [isToken, setIsToken] = useRecoilState(accessTokenState);
const [userInfo, setUserInfo] = useRecoilState(userInfoState);
const { data } = useQuery(FETCH_USER_LOGGED_IN);
const [userLogOut] = useMutation(LOG_OUT);
// 채팅방에서 헤더 비노출 처리를 위한 코드
const HIDDEN_HEADER = ['/chat/[chatInfo]'];
const isHiddenHeader = HIDDEN_HEADER.includes(router.pathname);
const [currentPage, setCurrentPage] = useState({
garden: false,
community: false,
chat: false,
charge: false,
profile: false,
});
useEffect(() => {
setUserInfo(data?.fetchUser);
// 현재 선택된 페이지에 맞는 헤더 메뉴 활성화를 위한 코드
setCurrentPage({
garden: false,
community: false,
chat: false,
charge: false,
profile: false,
[router.asPath.split('/')[1]]: true,
});
}, [data, router]);
const onClickRoute = (event: { currentTarget: { id: any } }) => {
router.push(`/${event.currentTarget.id}`);
};
const onClickLogOut = async () => {
try {
await userLogOut();
setIsToken('');
router.push('/garden');
} catch (error) {
if (error instanceof Error) alert(error.message);
}
};
const onClickMoveMypage = () => {
if (!isToken) {
alert('Please Login');
router.push('/signin');
} else {
router.push(`/profile/${userInfo.id}`);
}
};
return (
<LayoutHeaderUI
isHiddenHeader={isHiddenHeader}
onClickMoveMypage={onClickMoveMypage}
isToken={isToken}
data={data}
onClickLogOut={onClickLogOut}
currentPage={currentPage}
onClickRoute={onClickRoute}
/>
);
}
코드의 길이도 많이 줄어들고 props도 줄어드니 한결 보기 좋아진 것 같다.
변경 전 Presenter
<Header.WrapperLogo
id={'garden'}
onClick={props.onClickLogo}
></Header.WrapperLogo>
변경 후 Presenter
<Header.WrapperLogo
id={'garden'}
onClick={props.onClickRoute}
></Header.WrapperLogo>
- presenter는 코드 길이가 변하는건 없었다. 대신 로고, 메뉴1, 메뉴2등 메뉴별로 각각 다르게 바인딩 되어 있던 함수가 onClickRoute 함수 하나로 바인딩 되도록 변경되었다.
변경 전 Type 정의
export interface IHeaderUI {
isHiddenHeader: boolean;
onClickLogo: () => void;
onClickGarden: () => void;
onClickCommunity: () => void;
onClickChat: () => void;
onClickCharge: () => void;
onClickMoveMypage: () => void;
isToken: string;
data: any;
onClickLogOut: () => void;
onClickSignUp: () => void;
onClickSignIn: () => void;
currentPage: any;
}
변경 후 Type 정의
typescript를 위한 타입 정의도 아래와 같이 많이 줄일 수 있었다.
export interface IHeaderUI {
isHiddenHeader: boolean;
onClickMoveMypage: () => void;
isToken: string;
data: any;
onClickLogOut: () => void;
currentPage: any;
onClickRoute: (event: { currentTarget: { id: any } }) => void;
}