스프린트 일곱번째 미션이다.
점점 컴포넌트에 대한 이해도가 올라간다.
useHook
useMemo
useCallback을 통한 최적화를 계속 연습해야지.
근데 갈수록 의욕이 상실된다...
이유는..
분위가 다들 열심히 하는 분위기 되면
나도 따라가는데
뭔가 다들 하기 싫어하는 분위기?같아서
솔직히 하기 싫다.
나는 주부에 솔직히 제일 당장 취업이 아쉬운 것도 아닌데
나만 용쓰는 느낌인 것 같아서
... 힘이 안난다.
내가 힘이 너무 들어갔나????
취업해도 사람들과 관계가 좋을까...
전에도 개발직군 사람들과 종종 트러블이 있었기 때문에
일 자체에 근본적인 생각이 자꾸 나를 힘들게 한다.
일반 회사는 솔직히 나이가 걸림돌이 될 것 같고
상주 단기 프리랜서를 목표로 공부하긴 하지만
의욕이 많이 도태되어 있다.
그래도 이렇게 코드 리뷰 남기면서
나 자신과의 싸움을 해본다.
마지막 버킷 리스트인데 무조건 달려보자.. 리마인드 세팅..
기본 요구사항
체크리스트 [기본]
상품 상세
=> favoriteCount : 하트 개수
=> images : 상품 이미지
=> tags : 상품태그
=> name : 상품 이름
=> description : 상품 설명
상품 문의 댓글
=> image : 작성자 이미지
=> nickname : 작성자 닉네임
=> content : 작성자가 남긴 문구
=> description : 상품 설명
=> updatedAt : 문의글 마지막 업데이트 시간
1. form 내부 컴포넌트화
<form onSubmit={handleSubmit} onKeyDown={handleFormKeyDown}>
<div className="section-header">
<h2 className="title">상품 등록하기</h2>
<button className="btn-primary btn-sm" type="submit" disabled={!isFormValid}>
등록
</button>
</div>
<FileInput label="상품이미지" name="imgFile" value={values.imgFile} onChange={handleChange} />
<TextInput
label="상품명"
name="product"
value={values.product}
onChange={handleInputChange}
placeholder="상품명을 입력해주세요"
/>
<TextArea
label="상품 소개"
name="content"
value={values.content}
onChange={handleInputChange}
placeholder="상품 소개를 입력해주세요"
rows="10"
/>
<NumberInput
label="판매가격"
name="price"
value={values.price}
onChange={handleInputChange}
placeholder="판매 가격을 입력해주세요"
/>
<TagInput
label="태그"
name="tag"
onTagListChange={handleTagListChange}
placeholder="태그를 입력 후 Enter를 눌러 추가하세요"
/>
</form>
원래 input 그룹으로 묶어서 lable과 input으로 되었는데 전부 컴포넌트로 분리 시켰다.
2. api주소 상수화 중복개선
export async function getProducts(params = {}) {
const query = new URLSearchParams(params).toString();
try {
const response = await fetch(`${API_BASE_URL}/products?${query}`);
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
}
const body = await response.json();
return body;
} catch (error) {
console.error('Failed to fetch products:', error);
throw error;
}
}
export async function getProductById(productId) {
try {
const response = await fetch(`${API_BASE_URL}/products/${productId}`);
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
}
const body = await response.json();
return body;
} catch (error) {
console.error('Failed to fetch product:', error);
throw error;
}
}
자주쓰는 api 주소를 상수화 하여 코드를 줄였다.
3.useHook으로 중복된 useEffect 처리/ 코드 단순화
import { useState, useEffect } from 'react';
import { getProducts } from '../services/api';
const useProducts = (initialOrderBy, getPageSize) => {
const [orderBy, setOrderBy] = useState(initialOrderBy);
const [products, setProducts] = useState([]);
const [page, setPage] = useState(1);
const [pageSize, setPageSize] = useState(getPageSize());
const [totalPageNum, setTotalPageNum] = useState(0);
const [loading, setLoading] = useState(false);
const handleLoad = async ({ orderBy, page, pageSize }) => {
setLoading(true);
try {
const products = await getProducts({ orderBy, page, pageSize });
setProducts(products.list);
setTotalPageNum(Math.ceil(products.totalCount / pageSize));
} catch (error) {
console.error('Failed to load products:', error);
setProducts([]);
} finally {
setLoading(false);
}
};
useEffect(() => {
const handleResize = () => {
setPageSize(getPageSize());
};
window.addEventListener('resize', handleResize);
handleLoad({ orderBy, page, pageSize });
return () => {
window.removeEventListener('resize', handleResize);
};
}, [orderBy, page, pageSize]);
return {
orderBy,
setOrderBy,
products,
page,
setPage,
pageSize,
totalPageNum,
loading,
};
};
export default useProducts;
BestItem이랑 AllItem 두군데에서 불러오는 api를 하나의 useProductList라는 훅을 통해 코드량을 줄이고
가독성을 올려준다.
회고
미션 7을 마치면서 조금은 state 사용과 컴포넌트 사용에 자신감이 붙는다.
Presentational & Container 디자인 패턴 (1) | 2024.07.13 |
---|---|
CSS-in-JS의 장점과 단점 (0) | 2024.07.13 |
웹 페이지 렌더링 방식: CSR, SSR, SSG 각각의 특징 (0) | 2024.07.05 |
리액트 생명주기(life cycle) (0) | 2024.07.05 |
상품등록 페이지 코드리뷰 (1) | 2024.07.05 |