path parameter
참고) React Router: 파라미터와 쿼리 https://velog.io/@bigbrothershin/%ED%8C%8C%EB%9D%BC%EB%AF%B8%ED%84%B0%EC%99%80-%EC%BF%BC%EB%A6%AC
구조분해 할당
자식 컴포넌트에 props로 객체를 넘겨줄 때, 구조분해 할당을 해서 받아도 다시 객체의 키로 최종적으로 사용할 값에 접근하는 게 번거롭다.
//before
function Main() {
return (
...
{productList.map(data => (
<Product
key={data.id}
id={data.id}
name={data.name}
price={data.price}
rate={data.discount_rate}
description={data.description}
sizes={data.sizes}
url={data.thumbnail}
/>
))}
...
);
}
function Product({ id, name, price, rate, description, sizes, url }) {
return (
<article className="product">
<Link to={`/product-detail/${id}`}>
<img alt="상품 미리보기(샘플)" className="productImage" src={url} />
</Link>
<span className="productInfo">{description}</span>
<Link to={`/product-detail/${id}`} className="productName">
{name}
</Link>
<p className="priceInfo">
<span className="discountRate">{`${parseInt((1 - rate) * 100)}%`}</span>
<span className="productPrice">{`${parseInt(price)}원`}</span>
<span className="discountedPrice">{`${price * rate}원`}</span>
</p>
<p className="otherInfo">
{sizes.map((size, index) => (
<span key={index} className="productSize">
{size}
</span>
))}
<span className="productSize">1호</span>
<span className="productSize">2호</span>
<span className="delivery">무료배송</span>
</p>
</article>
);
}
Main 컴포넌트에서 map() 메서드를 사용하여 Product 컴포넌트를 여러번 찍어낼 때, props를 data(productList의 요소, 객체 형태)에서 하나하나 값을 꺼내서 전달하고 있다.
//after
function Main() {
return (
...
{productList.map(data => (
<Product
key={data.id}
data={data}
/>
))}
...
);
}
function Product({ data }) {
const { id, name, price, discount_rate, description, sizes, thumbnail } =
data;
return (
<article className="product">
<Link to={`/product-detail/${id}`}>
<img
alt="상품 미리보기(샘플)"
className="productImage"
src={thumbnail}
/>
</Link>
<span className="productInfo">{description}</span>
<Link to={`/product-detail/${id}`} className="productName">
{name}
</Link>
<p className="priceInfo">
<span className="discountRate">{`${parseInt(
(1 - discount_rate) * 100
)}%`}</span>
<span className="productPrice">{`${parseInt(price)}원`}</span>
<span className="discountedPrice">{`${price * discount_rate}원`}</span>
</p>
<p className="otherInfo">
{/* {sizes.map((size, index) => (
<span key={index} className="productSize">
{size}
</span>
))} */}
<span className="productSize">1호</span>
<span className="productSize">2호</span>
<span className="delivery">무료배송</span>
</p>
</article>
);
}
Product 컴포넌트에는 data 객체를 통째로 전달하고, Product 안에서 ({ data }) 로 props 자리에서 바로 구조분해 할당을 한다. 그 다음 .... data의 key들을 2차로 구조분해 할당 한다. 이때 주의할 점은, props가 data로 바뀌면서 백에서 받아온 data의 key명에 맞게 이름을 지정해주지 않게 되었다는 점이다. Product 컴포넌트 안에서 이름을 data의 key명에 맞춰 써야 한다.
"id" property가 없는 배열에 map() 사용할 때, key
{sizes.map((size, index) => (
<span key={index} className="productSize">
{size}
</span>
))}
map() 메서드의 두번째 인자를 사용해서 index를 받아 key에 줄 수 있다. 하지만 지양하는 방법이다. 그래서 다른 방안을 찾아보았다. 지금의 예시에서는 size의 값이 겹칠 리 없기 때문에 key에도 key={size} 하는 방법이 있다. 혹은 index와 size를 합쳐 새로운 고유 문자열을 만들어낼 수도 있다.
에러
Uncaught TypeError: Cannot read properties of undefined (reading '0')
at ProductDetail
The above error occurred in the <ProductDetail> component:
Uncaught TypeError: Cannot read properties of undefined (reading '0')
문제 진단
상품 상세 페이지에 접속했을 때, 현재 params로부터 가져온 id에 해당하는 상품의 데이터를 fetch하여 "product" state에 저장함. 그런데 페이지가 렌더링되지 않음. property를 읽을 수 없다고 하는데, 아무래도 fetch 되는 데 시간이 걸려서 product에 값이 아직 들어오지 않은 상태로 그 안에 접근하려고 하니 오류가 나는 것 같음.
해결 노력
1. 조건부 렌더링 : if(!product) { return null; } 해서 product에 값이 들어올 때까지 렌더링을 막아보려고 했지만 여전히 해결되지 않음.
2.
'TIL' 카테고리의 다른 글
[TIL-141] 위코드 42일차: (0) | 2022.03.06 |
---|---|
[TIL-140] 위코드 41일차: setState 하다가 발생한 에러 (0) | 2022.03.06 |
[TIL-138] 위코드 39일차: Project 1 - CSS (0) | 2022.03.03 |
[TIL-137] 위코드 38일차: JS 코드카타 (0) | 2022.03.02 |
[TIL-136] 위코드 37일차: Project1 - CSS / JS 코드카타 (0) | 2022.03.01 |