이번 프로젝트에서 내가 가장 고쳐야겠다고 싶었던 것 중에 꽤 높은 비율을 차지했던 사항이였다.
말로 장황하게 설명하는 것 보다 코드를 직접 보면서 고쳐나가는게 더 좋다고 보이는 파트이기에
어떤 방식으로 이런 변경을 하는지 살펴 보자!
return (
<>
<MainNavigation />
<div className={styles.pageContainer}>
<section className={styles.flexSection1}></section>
<section className={styles.flexSection2}>
<div className={styles.buttonContainer}>
<Link href="/newpost">
<button className={styles.button}><MdPostAdd /></button>
</Link>
</div>
<div className={styles.cateSticky}>
<div className={styles.categoryTitle}>
<p className={styles.categoryText}>카테고리</p>
</div>
<form className={styles.categoryForm}>
<div className={styles.categoryContainer}>
<div className={styles.cateMg}>
<input
type='checkbox'
id='3001'
className={styles.Checkboxes}
onChange={handleCategoryChange}
/>
<p className={styles.cateTexts}>커피 식 음료</p>
</div>
<div className={styles.cateMg}>
<input
type='checkbox'
id='3002'
className={styles.Checkboxes}
onChange={handleCategoryChange}
/>
<p className={styles.cateTexts}>영화 관람권</p>
</div>
<div className={styles.cateMg}>
<input
type='checkbox'
id='3003'
className={styles.Checkboxes}
onChange={handleCategoryChange}
/>
<p className={styles.cateTexts}>공연 관람권</p>
</div>
<div className={styles.cateMg}>
<input
type='checkbox'
id='3004'
className={styles.Checkboxes}
onChange={handleCategoryChange}
/>
<p className={styles.cateTexts}>숙박권</p>
</div>
<div className={styles.cateMg}>
<input
type='checkbox'
id='3005'
className={styles.Checkboxes}
onChange={handleCategoryChange}
/>
<p className={styles.cateTexts}>상품권</p>
</div>
<div className={styles.cateMg}>
<input
type='checkbox'
id='3006'
className={styles.Checkboxes}
onChange={handleCategoryChange}
/>
<p className={styles.cateTexts}>기타</p>
</div>
</div>
</form>
<MiniCategoryComponents className={styles.cateminibtn} selectedCategory={selectedCategory} onCategoryChange={handleCategoryChange}/>
</div>
<CommuPosts posts={posts} accessToken={accessToken} selectedCategory={selectedCategory} />
<div className={styles.pagination}>
{posts && posts.totalPages && currentPage > 1 && (
<button onClick={goToPreviousPageGroup}><Image src={'/svgs/Polygon2.svg'} alt="" width={26} height={26} className={styles.before} /></button>
)}
{posts && posts.totalPages && Array.from({ length: Math.min(PAGE_GROUP_SIZE, posts.totalPages - currentPage + 1) }, (_, index) => (
<button key={currentPage + index} onClick={() => handlePageChange(currentPage + index)} className={styles.pagebtn}>
{currentPage + index}
</button>
))}
{posts && posts.totalPages && currentPage + PAGE_GROUP_SIZE <= posts.totalPages && (
<button onClick={goToNextPageGroup}><Image src={'/svgs/Polygon3.svg'} alt="" width={26} height={26} /></button>
)}
</div>
</section>
</div>
</>
);
이번 프로젝트 중 하나였던 상품을 보여주는 페이지였다.
상품을 가져오는 코드는 잘 분리해서 하나의 컴포넌트로 출력했지만..
너무 장황하게 놓여있는 카테고리들과 페이지네이션 코드들이 메인에 바로 나와 있는걸 보면
아직 개발에 익숙치 않은 내가 봐도 어려운데 남이 이 코드를 봤을 때
정녕 개발자의 코드가 맞을까? 싶을 정도의 혼잡한 코드들이었다.
그럼 리팩토링을 시작하게 되었으니
이제 저 코드들을 컴포넌트화 시켜서 가독성을 높히는 작업을 시작해보자!
import styles from './Category.module.css';
export default function CategoryComponents({ handleCategoryChange }) {
return (
<>
<div className={styles.categoryTitle}>
<p className={styles.categoryText}>카테고리</p>
</div>
<form className={styles.categoryForm}>
<div className={styles.categoryContainer}>
<div className={styles.cateMg}>
<input
type='checkbox'
id='3001'
className={styles.Checkboxes}
onChange={handleCategoryChange}
/>
<p className={styles.cateTexts}>커피 식 음료</p>
</div>
<div className={styles.cateMg}>
<input
type='checkbox'
id='3002'
className={styles.Checkboxes}
onChange={handleCategoryChange}
/>
<p className={styles.cateTexts}>영화 관람권</p>
</div>
<div className={styles.cateMg}>
<input
type='checkbox'
id='3003'
className={styles.Checkboxes}
onChange={handleCategoryChange}
/>
<p className={styles.cateTexts}>공연 관람권</p>
</div>
<div className={styles.cateMg}>
<input
type='checkbox'
id='3004'
className={styles.Checkboxes}
onChange={handleCategoryChange}
/>
<p className={styles.cateTexts}>숙박권</p>
</div>
<div className={styles.cateMg}>
<input
type='checkbox'
id='3005'
className={styles.Checkboxes}
onChange={handleCategoryChange}
/>
<p className={styles.cateTexts}>상품권</p>
</div>
<div className={styles.cateMg}>
<input
type='checkbox'
id='3006'
className={styles.Checkboxes}
onChange={handleCategoryChange}
/>
<p className={styles.cateTexts}>기타</p>
</div>
</div>
</form>
</>
)
}
카테고리 코드들을 Category.jsx로 하나의 컴포넌트로 분리시켰다.
props를 통해 기존 handleCategoryChange의 기능을 유지 시켰다. 이런식으로 하나의 컴포넌트로 분리시키면
원래 위에 있던 페이지에 임포트하여 가져와서 출력만 시켜주면 될 것이다.
return (
<>
<MainNavigation />
<div className={styles.pageContainer}>
<section className={styles.flexSection1}></section>
<section className={styles.flexSection2}>
<div className={styles.buttonContainer}>
<Link href="/newpost">
<button className={styles.button}><MdPostAdd /></button>
</Link>
</div>
<div className={styles.cateSticky}>
<CategoryComponents handleCategoryChange={handleCategoryChange} />
<MiniCategoryComponents className={styles.cateminibtn} selectedCategory={selectedCategory} onCategoryChange={handleCategoryChange}/>
</div>
<CommuPosts posts={posts} accessToken={accessToken} selectedCategory={selectedCategory} />
<div className={styles.pagination}>
{posts && posts.totalPages && currentPage > 1 && (
<button onClick={goToPreviousPageGroup}><Image src={'/svgs/Polygon2.svg'} alt="" width={26} height={26} className={styles.before} /></button>
)}
{posts && posts.totalPages && Array.from({ length: Math.min(PAGE_GROUP_SIZE, posts.totalPages - currentPage + 1) }, (_, index) => (
<button key={currentPage + index} onClick={() => handlePageChange(currentPage + index)} className={styles.pagebtn}>
{currentPage + index}
</button>
))}
{posts && posts.totalPages && currentPage + PAGE_GROUP_SIZE <= posts.totalPages && (
<button onClick={goToNextPageGroup}><Image src={'/svgs/Polygon3.svg'} alt="" width={26} height={26} /></button>
)}
</div>
</section>
</div>
</>
);
맨 처음 장황했던 코드들이 하나의 컴포넌트를 임포트 해온 것 만으로 정말 간결한 코드로 변경되었다.
자 이제 그럼 밑에 페이지네이션 코드들도 분리 시켜보는 작업을 시작하자..
import Image from 'next/image';
import styles from "./Paginations.module.css";
export default function Pagination({ currentPage, posts, PAGE_GROUP_SIZE, handlePageChange, goToPreviousPageGroup, goToNextPageGroup }) {
return (
<div className={styles.pagination}>
{posts && posts.totalPages && currentPage > 1 && (
<button onClick={goToPreviousPageGroup}>
<Image src={'/svgs/Polygon2.svg'} alt="" width={26} height={26} className={styles.before} />
</button>
)}
{posts && posts.totalPages && Array.from({ length: Math.min(PAGE_GROUP_SIZE, posts.totalPages - currentPage + 1) }, (_, index) => (
<button key={currentPage + index} onClick={() => handlePageChange(currentPage + index)} className={styles.pagebtn}>
{currentPage + index}
</button>
))}
{posts && posts.totalPages && currentPage + PAGE_GROUP_SIZE <= posts.totalPages && (
<button onClick={goToNextPageGroup}>
<Image src={'/svgs/Polygon3.svg'} alt="" width={26} height={26} />
</button>
)}
</div>
);
}
원래 있던 코드들을 그대로 가져와 컴포넌트로 만들고 Props들을 전달만 한다면..
return (
<>
<MainNavigation />
<div className={styles.pageContainer}>
<section className={styles.flexSection1}></section>
<section className={styles.flexSection2}>
<div className={styles.buttonContainer}>
<Link href="/newpost">
<button className={styles.button}><MdPostAdd /></button>
</Link>
</div>
<div className={styles.cateSticky}>
<CategoryComponents handleCategoryChange={handleCategoryChange} />
<MiniCategoryComponents className={styles.cateminibtn} selectedCategory={selectedCategory} onCategoryChange={handleCategoryChange}/>
</div>
<CommuPosts posts={posts} accessToken={accessToken} selectedCategory={selectedCategory} />
<Pagination
currentPage={currentPage}
posts={posts}
PAGE_GROUP_SIZE={PAGE_GROUP_SIZE}
handlePageChange={handlePageChange}
goToPreviousPageGroup={goToPreviousPageGroup}
goToNextPageGroup={goToNextPageGroup}
/>
</section>
</div>
</>
);
정말 간단한 코드들로 변경된걸 볼 수 있다.
자 그럼 이렇게 컴포넌트들로 분리 한다면 장점이 있지 않겠는가?
1. 가독성
가독성 부분은 위에서 직접 확인한 것 처럼 코드 자체를 볼 때 이해하기 쉬워진다.
2. 모듈화하여 컴포넌트의 재 사용성
이렇게 코드를 작은 단위로 분리하여 관리한다면 코드를 재사용하기 쉬워질 것이다.
3. 유지보수
컴포넌트가 하나씩 독립적으로 작동하기 때문에 코드의 수정 및 유지보수가 매우 쉬워질 것이다.
4. 불 필요한 렌더링을 줄여 성능을 향상 시킨다.
컴포넌트가 필요한 경우에만 렌더링 될 것이기에 성능 자체가 당연히 향상 될 것이다.
오늘은 코드를 컴포넌트화 하여 분리 시키는 작업 및 장점에 대해서 알아보았다.
리팩토링하면서 오늘 소개한 부분만 분리 시키는 것이 아닌
필요하다고 판단 되는 부분들을 전부 컴포넌트화 하여 분리 시킬 예정이다.