메인페이지에서 실행되는 기능은 크게 두 가지이다. useEffect
훅에 따라 화면이 첫 렌더링될 때 상품 정보를 DB로부터 받아 이용하거나 사용자의 토큰 여부를 확인해 로그인을 유지시켜줄 수 있도록 서버에 검증 요청을 한다. 로그인 구현은 4번 글에 적어두었으므로 생략한다.
//Main.js
React.useEffect(() => {
//상품 리스트를 DB에서 받아와 리덕스에 저장한 뒤 화면에 표시
dispatch(prdActions.getPostDB());
//쿠키에 저장된 액세스 토큰이 존재한다면 서버로부터 유저 정보 받음
if(getCookie("is_login")){
dispatch(userActions.loginCheckDB());
}
},[])
...
{prd_list.map((p, idx) => {
if (idx !== 4) {//상품 포스트 하나하나 렌더링
return <Product {...p} key={p._id} idx={idx} />;
} else {//idx가 4인 경우 전체보기 소제목 추가
return (
<React.Fragment>
<Grid margin="10px 0" width="100%">
<Text bold size="25px" margin="20px 0 3px 0">
전체 보기
</Text>
<hr color="#F3F3F3"/>
</Grid>
<Product {...p} key={p._id} idx={idx} />
</React.Fragment>
);
}
})}
useEffect
에 별도 조건을 두지 않아 첫 렌더링 시에만 1회 실행된다. 상품 리스트와 회원 여부 검증을 서버에 요청한다.//Product.js
{props.idx < 4 ? ( //메인화면 배너 하단 상품 4개는 다른 레이아웃으로 표시
<Grid
width="275px"
height="260px"
_onClick={() => {
document.location.href=`/detail/${props.goodsId}`;
}}
>
<Image
src={props.prd_img}
width="275px"
height="190px"
margin="5px"
/>
<Grid center height="97px">
<div style={{ overflow: "hidden", width: "165px", margin: "auto" }}>
<ListName>{props.prd_name}</ListName>
</div>
<Grid is_flex width="50%" margin="0 auto" center>
{props.originPrice ? (
<Text size="13px" color="#FF6F61" bold margin="0">
{props.promotionPer}
<Line>{props.originPrice}</Line>
<Unit>원</Unit>
</Text>
) : null}
<Text margin="0" size="1.05em" bold margin="4px auto">
{price}
<span style={{ fontSize: "0.6em" }}>원</span>
</Text>
</Grid>
</Grid>
</Grid>
) : ( //그 외 제품은 아래 레이아웃으로 통일
/*생략*/
//prd.js (Redux module)
//DB로부터 상품 리스트를 받아 리덕스에 저장하는 API통신
const getPostDB = () =>{
return function (dispatch, getState, {history}){
dispatch(loading(true));
axios({
method: "get",
url:"http://13.125.249.241/api/items",
}).then(res => {
const post_list = res.data.result;
dispatch(setPost(post_list));
})
}
}
동적 라우팅을 설정하여 URL을 통해 id값을 전달한다. 리스트의 각 항목이 가지고 있는 고유한 id가 전달되므로 상세페이지 컴포넌트는 URL 경로에서 이 값을 가져와 일치하는 항목을 렌더링한다.
이 방식과 원리는 별도 게시물로 정리해뒀다.
TIL 49 | URL 경로로 매개변수를 전달하는 방법
//App.js
<Route path="/detail/:id" exact component={Detail}/>
//Post.js
<Grid
width="274px"
height="465px"
margin="10px 5px 50px 0"
bg="#f9fafa"
_onClick={() => {
document.location.href=`/detail/${props.goodsId}`;
}}
>
//Detail.js
//상품 디테일 페이지에서 옵션을 선택하여 장바구니에 담을 수 있음
const Detail = (props) => {
const id = props.match.params.id;
const dispatch = useDispatch();
const prd_list = useSelector((state) => state.prd.list);
const prd_idx = prd_list.findIndex((p) => p.goodsId == id);
const prd = prd_list[prd_idx];
//새로고침 등으로 리덕스에 일치하는 데이터가 존재하지 않는 경우
//DB에 해당 상품 정보 요청
React.useEffect(() => {
if (prd) {
return;
}
dispatch(prdActions.getOnePostDB(id));
}, []);
//Detail.js
return (
<React.Fragment>
{prd && ( //상품정보 존재 시 화면 렌더링
<Grid padding="60px 0 0 0" max_width="950px" margin="0 auto">
<div style={{ alignItems: "flex-start", display: "flex" }}>
<Image height="406px" src={prd.prd_img} />
<Grid>
<Grid is_flex>
<TextWrapper {...prd} />