오랫동안 포스팅을 하지 못했었는데,, 준석님의 예비군과 + 저의 알바 근무 때문에 시간이 잘 안맞았던 관계로 포스팅을 길게 하지 못했었습니다. 그래도 각자 작업을 했었고, 또 대체로 3차 목표로 잡았던 리팩토링은 대부분 로직분리가 많았으므로, 딱히 포스팅할 내용도 없었네요.
● 3차 목표
❍ Page
CopyPopUp 페이지 삭제하기query 관련 함수 useQuery, useMutation 모두 훅으로 처리하기ESC 버튼 누를시 이전 페이지로 이동 함수 util로 빼기 중복으로 사용되고 있습니다. 추가로 다른 PopUP 페이지 혹은 PopUp Component에도 적용하면 좋지 않을까요?
❍ FeedPopUP(다은)
isSucess와 getGuestFeed.isSucess 일 때 컴포넌트 구성이 완전 중복인 것 같은데 이를 컴포넌트로 분리 할 수 있을까?query를 훅으로 분리하면 가능할 것 같기도?생각이 복잡해지는 페이지군요.. 리팩토링이 매우 필요한 페이지같아요
❍ Home(준석)
useInfinityQuery 훅으로 뺴기Wellcome PopUp 컴포넌트로 분리하기window.innerWidth에 따라 화면 분기 처리한 부분과 각 토큰 값 부분 분기 처리한 부분 컴포넌트로 분리할 수 있지 않을까? 그러게요 이거 해봐야겟내요.styled 처리하자..
❍ Info(다은)
Error Message 분리하기mutation 훅으로 분리jsx 의 회원가입과 회원 수정 부분이 코드가 같은데, 페이지를 분리하는 것이 좋을지. 같은 컴포넌트로 관리하는게 좋을까?여기도 팝업 state하나로 관리할 수 있어요.핸들러다 빼버렷음 좋겟어요.. 흑흐긎ㄷ릔믉!!!니ㅏㅇ럼니ㅏ얼!!- 줼
님 왜 styled안썻어잉?
❍ 🚩MyPage(준석)
임포트지옥.. 해결할 수있는 방법 업갯조?..infinity query 훅으로 관리하기각각의 query (useQuery, useMutation) 모두 훅으로 관리하기분기처리 정리하기데이터가 모두 로딩인 경우 LoadingComponent데이터를 모두 받아온 경우 Container
ListBox 컴포넌트로 분리하기currenntTab 숫자에 따라 데이터만 다르고 jsx 형식은 같기에 컴포넌트로 분리하는게 좋지 않을까? 저도 이생각했어요
❍ UserPage(준석)
infinity query 훅으로 관리하기각각의 query (useQuery, useMutation) 모두 훅으로 관리하기UserPage의 형식 또한 myPage의 형식과 같다.
❍ WalkEditing & WalkFeed & WalkPosting(준석)
useQuery 부분 훅으로 처리하기- effect를 통한 화면 분기처리 router DOm의 loder로 처리하는게 좋지 않을까?
- 이해하지못햇으빈다.
❍ WalkFeed(다은)
중간에 껴잇는 state.. 불편합니다..
❍ WalkMate (다은)
infinityQuery 처리 부분 훅으로 처리하기Filter에 따른 분기처리 Component로 분리
● 오늘 리팩토링하면서 느낀점
❍ import * as SC
프로젝트를 진행하면서 멘토님께서 styled로 쓰인 로직은 'SC'로 불러와 styled인지 아니면 컴포넌트를 불러오는건지 로직 내에서 구분하는게 좋다라는 말씀을 해주셨던게 기억나, 준석님과 함께 styled와 그냥 컴포넌트와의 로직구분을 진행하였습니다. 실제로도 코드를 짜면서 + 코드 리팩토링을 진행할 때 이게 styled로 쓰인건지 아니면 컴포넌트로 쓰인건지에 대한 계속 찾아보면서 코드를 봐야했던게 굉장히 불편했습니다. 확실히 styled로 분리를 해놓으니.. 실제로 DX가 굉장히 증진되는걸 매우 느꼈습니다•••
아래는 리팩토링 하기 이전의 코드인데요,
if (accessToken) {
return (
<nav className="hidden max-sm:block bg-white fixed bottom-[16px] rounded-[30px] left-1/2 -translate-x-[50%] z-[800] shadow-xl">
<ul className="flex gap-8 py-3 px-10 max-sm:px-7 max-sm:gap-7">
<NavTab route="Home" />
<NavTab route="WalkMate" />
<NavTab route="WalkPosting" />
<NavTab route="Mypage" />
<li className=" cursor-pointer">
<Logout className="w-9 h-9" onClick={handleClick} />
</li>
</ul>
</nav>
);
} else {
return (
<nav className="hidden max-sm:block bg-white fixed bottom-[16px] rounded-[30px] left-1/2 -translate-x-[50%] z-[800] shadow-xl">
<ul className="flex gap-8 py-3 px-10">
<NavTab route="Home" />
<li className="cursor-pointer">
<Login className="w-9 h-9" onClick={handleClick} />
</li>
</ul>
</nav>
);
}
}
아래는 리팩토링 한 이후의 코드입니다.
if (accessToken) {
return (
<SC.NavContainer>
<SC.HostList>
<NavTab route="Home" />
<NavTab route="WalkMate" />
<NavTab route="WalkPosting" />
<NavTab route="Mypage" />
<li className=" cursor-pointer">
<Logout className="w-9 h-9" onClick={handleClick} />
</li>
</SC.HostList>
</SC.NavContainer>
);
} else {
return (
<SC.NavContainer>
<SC.HostList>
<NavTab route="Home" />
<li className="cursor-pointer">
<Login className="w-9 h-9" onClick={handleClick} />
</li>
</SC.HostList>
</SC.NavContainer>
);
}
}
확실히 SC.로 불러오게 되면서 styled 컴포넌트라는 것을 구분할 수 있었고 다른 일반 컴포넌트는 NavTab 인 것을 개발자 입장에서 확실히 구분할 수 있다는 것을 + 매우 편안함을 느낄 수 있었습니다.
이외에도 import 문이 짧아짐으로써, 눈이 굉장히 편해지는 것도 느낄 수 있었습니다.
import { ReactComponent as Man } from '@/assets/label/man.svg';
import { ReactComponent as Woman } from '@/assets/label/woman.svg';
import Button from '@/common/button/Button.tsx';
import {
ErrorNotice,
InputContainer,
InputText,
Label,
} from '@/common/input/Input.styled.tsx'; // SC부분
import AlertText from '@/common/popup/AlertText';
import { PopupBackGround } from '@/common/popup/popup.styled.tsx';
import Popup from '@/common/popup/Popup.tsx';
import { Container, Form, RadioBox } from '@/components/pet/petInfo.styled.tsx';
import PetProfile from '@/components/pet/petProfile/PetProfile.tsx';
import usePatchFormMutation from '@/hook/api/mutation/usePatchFormMutation';
import usePostFormMutation from '@/hook/api/mutation/usePostFormMutation';
SC문을 하나씩 불러오면서 import문이 길어지곤 했는데, as SC로 불러오게 되면서
import { ReactComponent as Man } from '@/assets/label/man.svg';
import { ReactComponent as Woman } from '@/assets/label/woman.svg';
import Button from '@/common/button/Button.tsx';
import * as SCINPUT from '@/common/input/Input.styled.tsx';
import AlertText from '@/common/popup/AlertText';
import * as SC from '@/common/popup/popup.styled.tsx';
import Popup from '@/common/popup/Popup.tsx';
import * as SCPET from '@/components/pet/petInfo.styled.tsx';
import PetProfile from '@/components/pet/petProfile/PetProfile.tsx';
import usePatchFormMutation from '@/hook/api/mutation/usePatchFormMutation';
import usePostFormMutation from '@/hook/api/mutation/usePostFormMutation';
위으 import문이 깔끔히 정리되는 것을 실감할 수 있었습니다..!!
❍ useLocalStorage의 setter함수는 useState의 setter와 .. 구조가 같다!
그냥 일반적인 ..? 굉장히 별거 아닌 부분일 수도 있겠습니다만, 코드를 하나씩 모두 둘러보면서 에러가 나는 부분이 있었는데요,
import { SetValue } from 'usehooks-ts'; // SetValue가 없어서 불러올수없는 에러발생
type Prop = {
setFirstVisited: SetValue<boolean>;
};
제가 짰던 코드가 아니였어서, SetValue의 값을 불러 올 수 없다는 에러가 발생하고 있었습니다. ?? 이거 왜 에러 발생하고 있는데 수정안하셨지..? 라는 생각이 들었는데요.. 보니까 prop으로 받아오는 setFirstVisitied가 뭐지? 하고 추적을 해보니
const [isFirstVisited, setFirstVisited] = useLocalStorage(
'firstVisited',
true,
);
useLocalStorage에서 쓰이는 setter함수더군용. 그래서 흠 그럼 이 함수를 prop으로 받고있는데, type이 없다는 소리니.. type이 뭘까 하고 찾아보았습니다. (VScode에러에서도 해결책을 알려주고 있지 않았습니다.)
useHooks의 공식문서를 찾아보니 쉽게 해결할 수 있었습니다.
useLocalStorage
Discover how to use useLocalStorage from usehooks-ts
usehooks-ts.com
import {
Dispatch,
SetStateAction,
useCallback,
useEffect,
useState,
} from 'react'
import { useEventCallback, useEventListener } from 'usehooks-ts'
declare global {
interface WindowEventMap {
'local-storage': CustomEvent
}
}
// 해결할 수 있었던 부분
type SetValue<T> = Dispatch<SetStateAction<T>>
export function useLocalStorage<T>(
.....
즉 SetValue는 useState의 SetStateAction 구조와 동일하다고 나와있었습니다.
그래서 아래와 같이 코드를 수정하니, 에러를 해결할 수 있었습니다.ㅎ_ㅎ
type Prop = {
setFirstVisited: React.Dispatch<React.SetStateAction<boolean>>;
};
오랫동안 포스팅을 하지 못했었는데,, 준석님의 예비군과 + 저의 알바 근무 때문에 시간이 잘 안맞았던 관계로 포스팅을 길게 하지 못했었습니다. 그래도 각자 작업을 했었고, 또 대체로 3차 목표로 잡았던 리팩토링은 대부분 로직분리가 많았으므로, 딱히 포스팅할 내용도 없었네요.
● 3차 목표
❍ Page
CopyPopUp 페이지 삭제하기query 관련 함수 useQuery, useMutation 모두 훅으로 처리하기ESC 버튼 누를시 이전 페이지로 이동 함수 util로 빼기 중복으로 사용되고 있습니다. 추가로 다른 PopUP 페이지 혹은 PopUp Component에도 적용하면 좋지 않을까요?
❍ FeedPopUP(다은)
isSucess와 getGuestFeed.isSucess 일 때 컴포넌트 구성이 완전 중복인 것 같은데 이를 컴포넌트로 분리 할 수 있을까?query를 훅으로 분리하면 가능할 것 같기도?생각이 복잡해지는 페이지군요.. 리팩토링이 매우 필요한 페이지같아요
❍ Home(준석)
useInfinityQuery 훅으로 뺴기Wellcome PopUp 컴포넌트로 분리하기window.innerWidth에 따라 화면 분기 처리한 부분과 각 토큰 값 부분 분기 처리한 부분 컴포넌트로 분리할 수 있지 않을까? 그러게요 이거 해봐야겟내요.styled 처리하자..
❍ Info(다은)
Error Message 분리하기mutation 훅으로 분리jsx 의 회원가입과 회원 수정 부분이 코드가 같은데, 페이지를 분리하는 것이 좋을지. 같은 컴포넌트로 관리하는게 좋을까?여기도 팝업 state하나로 관리할 수 있어요.핸들러다 빼버렷음 좋겟어요.. 흑흐긎ㄷ릔믉!!!니ㅏㅇ럼니ㅏ얼!!- 줼
님 왜 styled안썻어잉?
❍ 🚩MyPage(준석)
임포트지옥.. 해결할 수있는 방법 업갯조?..infinity query 훅으로 관리하기각각의 query (useQuery, useMutation) 모두 훅으로 관리하기분기처리 정리하기데이터가 모두 로딩인 경우 LoadingComponent데이터를 모두 받아온 경우 Container
ListBox 컴포넌트로 분리하기currenntTab 숫자에 따라 데이터만 다르고 jsx 형식은 같기에 컴포넌트로 분리하는게 좋지 않을까? 저도 이생각했어요
❍ UserPage(준석)
infinity query 훅으로 관리하기각각의 query (useQuery, useMutation) 모두 훅으로 관리하기UserPage의 형식 또한 myPage의 형식과 같다.
❍ WalkEditing & WalkFeed & WalkPosting(준석)
useQuery 부분 훅으로 처리하기- effect를 통한 화면 분기처리 router DOm의 loder로 처리하는게 좋지 않을까?
- 이해하지못햇으빈다.
❍ WalkFeed(다은)
중간에 껴잇는 state.. 불편합니다..
❍ WalkMate (다은)
infinityQuery 처리 부분 훅으로 처리하기Filter에 따른 분기처리 Component로 분리
● 오늘 리팩토링하면서 느낀점
❍ import * as SC
프로젝트를 진행하면서 멘토님께서 styled로 쓰인 로직은 'SC'로 불러와 styled인지 아니면 컴포넌트를 불러오는건지 로직 내에서 구분하는게 좋다라는 말씀을 해주셨던게 기억나, 준석님과 함께 styled와 그냥 컴포넌트와의 로직구분을 진행하였습니다. 실제로도 코드를 짜면서 + 코드 리팩토링을 진행할 때 이게 styled로 쓰인건지 아니면 컴포넌트로 쓰인건지에 대한 계속 찾아보면서 코드를 봐야했던게 굉장히 불편했습니다. 확실히 styled로 분리를 해놓으니.. 실제로 DX가 굉장히 증진되는걸 매우 느꼈습니다•••
아래는 리팩토링 하기 이전의 코드인데요,
if (accessToken) {
return (
<nav className="hidden max-sm:block bg-white fixed bottom-[16px] rounded-[30px] left-1/2 -translate-x-[50%] z-[800] shadow-xl">
<ul className="flex gap-8 py-3 px-10 max-sm:px-7 max-sm:gap-7">
<NavTab route="Home" />
<NavTab route="WalkMate" />
<NavTab route="WalkPosting" />
<NavTab route="Mypage" />
<li className=" cursor-pointer">
<Logout className="w-9 h-9" onClick={handleClick} />
</li>
</ul>
</nav>
);
} else {
return (
<nav className="hidden max-sm:block bg-white fixed bottom-[16px] rounded-[30px] left-1/2 -translate-x-[50%] z-[800] shadow-xl">
<ul className="flex gap-8 py-3 px-10">
<NavTab route="Home" />
<li className="cursor-pointer">
<Login className="w-9 h-9" onClick={handleClick} />
</li>
</ul>
</nav>
);
}
}
아래는 리팩토링 한 이후의 코드입니다.
if (accessToken) {
return (
<SC.NavContainer>
<SC.HostList>
<NavTab route="Home" />
<NavTab route="WalkMate" />
<NavTab route="WalkPosting" />
<NavTab route="Mypage" />
<li className=" cursor-pointer">
<Logout className="w-9 h-9" onClick={handleClick} />
</li>
</SC.HostList>
</SC.NavContainer>
);
} else {
return (
<SC.NavContainer>
<SC.HostList>
<NavTab route="Home" />
<li className="cursor-pointer">
<Login className="w-9 h-9" onClick={handleClick} />
</li>
</SC.HostList>
</SC.NavContainer>
);
}
}
확실히 SC.로 불러오게 되면서 styled 컴포넌트라는 것을 구분할 수 있었고 다른 일반 컴포넌트는 NavTab 인 것을 개발자 입장에서 확실히 구분할 수 있다는 것을 + 매우 편안함을 느낄 수 있었습니다.
이외에도 import 문이 짧아짐으로써, 눈이 굉장히 편해지는 것도 느낄 수 있었습니다.
import { ReactComponent as Man } from '@/assets/label/man.svg';
import { ReactComponent as Woman } from '@/assets/label/woman.svg';
import Button from '@/common/button/Button.tsx';
import {
ErrorNotice,
InputContainer,
InputText,
Label,
} from '@/common/input/Input.styled.tsx'; // SC부분
import AlertText from '@/common/popup/AlertText';
import { PopupBackGround } from '@/common/popup/popup.styled.tsx';
import Popup from '@/common/popup/Popup.tsx';
import { Container, Form, RadioBox } from '@/components/pet/petInfo.styled.tsx';
import PetProfile from '@/components/pet/petProfile/PetProfile.tsx';
import usePatchFormMutation from '@/hook/api/mutation/usePatchFormMutation';
import usePostFormMutation from '@/hook/api/mutation/usePostFormMutation';
SC문을 하나씩 불러오면서 import문이 길어지곤 했는데, as SC로 불러오게 되면서
import { ReactComponent as Man } from '@/assets/label/man.svg';
import { ReactComponent as Woman } from '@/assets/label/woman.svg';
import Button from '@/common/button/Button.tsx';
import * as SCINPUT from '@/common/input/Input.styled.tsx';
import AlertText from '@/common/popup/AlertText';
import * as SC from '@/common/popup/popup.styled.tsx';
import Popup from '@/common/popup/Popup.tsx';
import * as SCPET from '@/components/pet/petInfo.styled.tsx';
import PetProfile from '@/components/pet/petProfile/PetProfile.tsx';
import usePatchFormMutation from '@/hook/api/mutation/usePatchFormMutation';
import usePostFormMutation from '@/hook/api/mutation/usePostFormMutation';
위으 import문이 깔끔히 정리되는 것을 실감할 수 있었습니다..!!
❍ useLocalStorage의 setter함수는 useState의 setter와 .. 구조가 같다!
그냥 일반적인 ..? 굉장히 별거 아닌 부분일 수도 있겠습니다만, 코드를 하나씩 모두 둘러보면서 에러가 나는 부분이 있었는데요,
import { SetValue } from 'usehooks-ts'; // SetValue가 없어서 불러올수없는 에러발생
type Prop = {
setFirstVisited: SetValue<boolean>;
};
제가 짰던 코드가 아니였어서, SetValue의 값을 불러 올 수 없다는 에러가 발생하고 있었습니다. ?? 이거 왜 에러 발생하고 있는데 수정안하셨지..? 라는 생각이 들었는데요.. 보니까 prop으로 받아오는 setFirstVisitied가 뭐지? 하고 추적을 해보니
const [isFirstVisited, setFirstVisited] = useLocalStorage(
'firstVisited',
true,
);
useLocalStorage에서 쓰이는 setter함수더군용. 그래서 흠 그럼 이 함수를 prop으로 받고있는데, type이 없다는 소리니.. type이 뭘까 하고 찾아보았습니다. (VScode에러에서도 해결책을 알려주고 있지 않았습니다.)
useHooks의 공식문서를 찾아보니 쉽게 해결할 수 있었습니다.
useLocalStorage
Discover how to use useLocalStorage from usehooks-ts
usehooks-ts.com
import {
Dispatch,
SetStateAction,
useCallback,
useEffect,
useState,
} from 'react'
import { useEventCallback, useEventListener } from 'usehooks-ts'
declare global {
interface WindowEventMap {
'local-storage': CustomEvent
}
}
// 해결할 수 있었던 부분
type SetValue<T> = Dispatch<SetStateAction<T>>
export function useLocalStorage<T>(
.....
즉 SetValue는 useState의 SetStateAction 구조와 동일하다고 나와있었습니다.
그래서 아래와 같이 코드를 수정하니, 에러를 해결할 수 있었습니다.ㅎ_ㅎ
type Prop = {
setFirstVisited: React.Dispatch<React.SetStateAction<boolean>>;
};