React 쇼핑몰 클론코딩 : 5. 전체 상품과 상세페이지(API, Dynamic route URL)

Gom·2021년 4월 10일
4

Project

목록 보기
8/15
post-thumbnail

📝 메인 : DB의 상품 리스트 표시

로직

메인페이지에서 실행되는 기능은 크게 두 가지이다. 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회 실행된다. 상품 리스트와 회원 여부 검증을 서버에 요청한다.
  • DB에서 응답받은 상품 리스트를 화면에 렌더링한다. 1~4번 상품은 포스트 레이아웃을 다르게 하기 위해 조건문을 두었다. 레이아웃의 차이는 Product 컴포넌트 안에서 다시 한 번 인덱스를 확인하도록 하였다.

//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}/>

1. 동적 라우팅으로 URL을 통해 매개변수 id를 전달한다.

2. 각 상품포스팅 컴포넌트는 클릭 시 상품 상세 페이지로 이동하는 함수를 포함하고 있다.

//Post.js

 <Grid
          width="274px"
          height="465px"
          margin="10px 5px 50px 0"
          bg="#f9fafa"
          _onClick={() => {
            document.location.href=`/detail/${props.goodsId}`;
          }}
        >

3. 상세 페이지는 URL로 받아온 매개변수 값을 가지고 상품 리스트 중 일치하는 값을 찾아 렌더링한다.

3-1. 일치여부 확인 및 필요 시 DB에서 데이터 받아오기

//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));
  }, []);

3-2. 일치하는 상품 존재 시 해당 데이터로 화면 렌더링

//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} /> 
profile
안 되는 이유보다 가능한 방법을 찾을래요

0개의 댓글