editRefect
해당 컴포넌트는 유저의 자소서 리스트를 관리하기 위한 목적으로 작성되었습니다.
EDIT라는 명칭은 의미를 파악하기 힘들었습니다.
이전 문제와 동일하게 컴포넌트의 관심사 분리 & 매직넘버 문제가 있었습니다.
Props드릴링 문제도 발생했습니다.
상세 문제점 파악
표현이 애매한 도메인명
EDIT : 편집 무엇을 편집?
복잡한 페이지 라우팅 구조 & 명칭
myEssay : 자소서 확인 페이지
edit : 자소서 작성 페이지 라우팅
edit essay=2 : 자소서 수정 페이지
idx로 이루어진 map 키값
EDIT 해결 방안
대표 도메인명 수정
coverLetter: 자기소개서
복잡한 라우팅 & 명칭 개선
coverLetter : 자소서 확인 페이지
coverLetter/new : 자소서 작성 페이지
coverLetter/[id]/edit: 자소서 편집 페이지
컴포넌트 관심사 분류
UUID4()를 키값으로 사용하기
트리가 깊은 경우 리덕스 활용
자기소개서 리팩토링 적용전
유저 자소서 리스트 관리
유저가 선택한 자소서 넘버 상태를 관리 하기 위한 로직이 Props드릴링 구조의 주요 원인이라 판단되었습니다.
유저 자소서 생성 & 편집
생성과 편집의 스타일이나 로직이 비슷하다는 이유로 하나의 컴포넌트에서 이를 처리하려 했던 안일한 접근이 문제였습니다.
isEdit
상태에 대한 의존도가 높아져 가독성이 떨어지고 유지보수 측면에서 비효율적이었습니다.삼항 연산자를 이용하여 기능을 분류하는 방식은 절차적인 성향의 코드에 가까워 컴포넌트 간의 의존도를 높이고 유지보수 측면에서 매우 비효율적이며 가독성을 떨어트렸습니다.
[ 해결방안
]
컴포넌트 분리: 생성 기능과 편집 기능을 별도의 컴포넌트로 분리하였습니다. 커스텀 훅 활용: 비슷하고 겹치는 비즈니스 로직은 커스텀 훅으로 분리하여 상태 관리를 효율적으로 하였습니다.
명칭 변경:
handle ~~
형태의 불명확한 명칭을 최대한 직관적으로 변경하였습니다.고유 키 값 사용: 서버에서 id 값을 지정해주기 때문에 key 값에 크게 신경 쓰지 않았으나, CRUD 관련 컴포넌트의 맵핑에서는 key 값을 유니크한 값으로 지정하는 것이 옳다고 판단하여
uuid4()
를 채택하였습니다.
EDIT 리팩토링 적용전 코드
주석이 없으면 이해할수 없는 코드와 구조
리팩토링 적용후(코드 일부)
const CoverLetterEdit = () => {
const [coverLetterTitle, setCoverLetterTitle] = useState < string > "";
const router = useRouter();
const moveCoverLetterMainPage = "/coverLetter";
const { id } = router.query;
const { qnaList, setQnAList, deleteQnAList, changeQnAList, addQnAList } =
useCoverLetterCreatorLogic();
const {
loading,
targetQnAData,
getDetailEssayList,
coverLetterMainTitle,
changeCoverLetter,
deleteCoverLetter,
} = useCoverLetterManager();
useEffect(() => {
getDetailEssayList(Number(id));
}, []);
useEffect(() => {
if (!loading) {
setQnAList(targetQnAData);
setCoverLetterTitle(coverLetterMainTitle);
}
}, [targetQnAData]);
if (loading) return <p>로딩중...</p>;
return (
<CoverLetterCreatorContainer>
<MainTitle>자소서 수정하기</MainTitle>
<CoverLetterTitle
value={coverLetterTitle}
onChange={(e) => setCoverLetterTitle(e.target.value)}
placeholder="자소서 제목"
></CoverLetterTitle>
{qnaList.map((qna, i) => (
<CoverLetterQuestionItems
key={qna.qnaId}
item={qna}
onDelete={deleteQnAList}
onUpdate={changeQnAList}
></CoverLetterQuestionItems>
))}
<BiPlusStyled onClick={addQnAList}></BiPlusStyled>
<ControllerBtns>
<CustomButton
Size={{ width: "150px", font: "20px" }}
onClick={() => router.push(moveCoverLetterMainPage)}
text={"뒤로가기"}
/>
<CustomButton
Size={{ width: "150px", font: "20px" }}
onClick={() => deleteCoverLetter(Number(id))}
text={"삭제하기"}
/>
<CustomButton
Size={{ width: "150px", font: "20px" }}
onClick={() =>
changeCoverLetter(Number(id), coverLetterTitle, qnaList)
}
text={"수정완료"}
/>
</ControllerBtns>
</CoverLetterCreatorContainer>
);
};
export default CoverLetterEdit;
비즈니스 로직을 외부로 분리하여 가독성과 관리가 용이 해졌습니다.
비즈니스 로직을 커스텀훅으로 분리하여 재 사용할 수 있는 가능성이 생겼습니다.
유지보수 측면에서 효율적으로 변했습니다.
컴포넌트 자체는 UI렌더링과 간단한 상태관리에 집중되어 단일 책임 원칙을 지켰습니다.
리팩토링 후 구조
컴포넌트
📦CoverLetter
┣ 📂edit
┃ ┗ 📜CoverLetterEdit.tsx
┣ 📂hooks
┃ ┣ 📜useControlTemplate.ts
┃ ┣ 📜useCoverLetterCreatorLogic.ts
┃ ┗ 📜useCoverLetterManager.ts
┣ 📂new
┃ ┣ 📜CoverLetterCreator.tsx
┃ ┗ 📜CoverLetterQuestionItems.tsx
┣ 📜CoverLetter.tsx
┣ 📜CoverLetterItems.tsx
┣ 📜CoverLetterList.tsx
┗ 📜CoverLetterPreView.tsx
라우팅
📦coverLetter
┣ 📂new
┃ ┗ 📜index.tsx
┣ 📂[id]
┃ ┗ 📂edit
┃ ┃ ┗ 📜index.tsx
┗ 📜index.tsx
리덕스
📦Essay
┣ 📂server
┃ ┣ 📜actions.tsx
┃ ┣ 📜reducer.tsx
┃ ┗ 📜types.tsx
┗ 📂user
┃ ┣ 📜actions.ts
┃ ┣ 📜reducer.ts
┃ ┗ 📜types.ts
Last updated