[Wikea] 상품 정렬 기능

sue·2021년 3월 24일
0

Wikea Project

목록 보기
5/6

구현 기능

  • 리스트 페이지에서 출력하는 상품 목록을 특정 기준으로 정렬할 수 있도록 구현했다.
  • 기본값은 신제품이며, 낮은가격 순, 높은 가격 순, 이름 순, 고객평가 순, 가장 인기있는 순으로 세부 항목을 선택할 수 있다.

구현 코드

리스트 데이터를 디스패치할 때, 오프셋 값과 카테고리 아이디만 넘겨주었던 기존 코드에서 filter 속성을 추가해 함께 넘겨준다.

ListPage.jsx

import React, { useEffect, useState, useRef } from 'react';
import qs from 'qs';
import { useDispatch, useSelector } from 'react-redux';
import { getList, loadMoreList } from 'modules/product/thunk';
import List from 'components/list/List';
import ButtonFix from 'components/common/buttons/ButtonFix';
import Loading from 'components/common/Loading';

export default function ListPage({ location, match }) {
  const currentOffset = useRef(24);
  const beforeId = useRef(0);
  const query = qs.parse(location.search, { ignoreQueryPrefix: true });
  const [currentFilter, setCurrentFilter] = useState(0);
  const { getListLoading, getListData, getListError, hasMore } = useSelector(
    state => state.product
  );
  const dispatch = useDispatch();
  const { id } = match.params;
  
  const onLoadMore = () => {
    dispatch(
      loadMoreList({
        cateId: id,
        offset: currentOffset.current,
        filter: currentFilter,
      })
    );
    currentOffset.current += 24;
  };
 
  useEffect(() => {
    document.title = `IKEA | ${query.sc}`;
    if (id !== beforeId.current) {
      setCurrentFilter(0);
    }
    dispatch(getList({ cateId: id, filter: currentFilter }));
    beforeId.current = id;
  }, [dispatch, id, currentFilter, query.sc]);

  if (getListLoading) return <Loading />;
  if (!getListData) return null;
  if (getListError) return <div>에러페이지</div>;

  return (
    <>
      <List
        title={query.sc}
        data={getListData}
        currentFilter={currentFilter}
        setCurrentFilter={setCurrentFilter}
        onLoadMore={onLoadMore}
        hasMoreList={hasMore}
      />
      <ButtonFix />
    </>
  );
}

리스트 페이지에서 정렬 버튼을 클릭하면 filterOpen 상태를 true값으로 변경하고, filterOpen이 true 상태일 때 ListFilter 컴포넌트를 출력한다.

List.jsx


function List({
  title,
  data,
  currentFilter,
  setCurrentFilter,
  onLoadMore,
  hasMoreList,
}) {
  const [filterOpen, setFilterOpen] = useState(false);
  const [listState, setListState] = useState(0);
  const { userInfo } = useSelector(state => state.user);

  return (
    <>
      <ListWrapper active={listState === 1}>
        <h1>{title}</h1>
        <div>
          <ul>
            <li>
              <ButtonRound>전체 상품</ButtonRound>
            </li>
            <li>
              <ButtonRound gray onClick={() => setFilterOpen(true)}>
                정렬
              </ButtonRound>
            </li>
          </ul>
          <div>
            <span>{`${data && data.length}`}</span>
            <b onClick={() => setListState(0)}>제품</b>
            <b onClick={() => setListState(1)}>디지털 쇼룸</b>
          </div>
        </div>
        <ListContainer>
          {data ? (
            data.length === 0 ? (
              <Error text="카테고리에 해당하는 아이템이 없습니다" grid />
            ) : (
              data.map(item => (
                <ListItem
                  listState={listState}
                  data={item}
                  key={item.id}
                  userInfo={userInfo}
                />
              ))
            )
          ) : null}
        </ListContainer>
      </ListWrapper>
      // ...
      {filterOpen && (
        <ListFilter
          setFilterOpen={setFilterOpen}
          currentFilter={currentFilter}
          setCurrentFilter={setCurrentFilter}
        />
      )}
    </>
  );
}
export default List;

ListFilter 컴포넌트에서는 선택된 필터 옵션을 출력하기 위한 코드를 작성한다.

ListFilter.jsx


export default function ListFilter({
  setFilterOpen,
  currentFilter,
  setCurrentFilter,
}) {
  const [filterVisible, setFilterVisible] = useState(true);
  const [filterDown, setFilterDown] = useState(false);

  const onChangeRadio = (e) => {
    const currentNumber = parseInt(e.target.value, 10);
    const selected = Filters.find((v) => v.id === currentNumber);
    setCurrentFilter(selected.id);
  };

  const filterClose = () => {
    setTimeout(() => {
      setFilterOpen(false);
    }, 300);
    setFilterVisible(false);
  };
  return (
    <FilterContainer>
      <FilterBox visible={filterVisible}>
        <FilterTop down={filterDown}>
          <i>
            <RiAddLine onClick={filterClose} />
          </i>
          <div>
            <h2>정렬</h2>
            <i>
              <RiArrowDownSLine onClick={() => setFilterDown(!filterDown)} />
            </i>
          </div>
        </FilterTop>
        <FilterBottom down={filterDown}>
          {Filters.map((v) => (
            <div key={v.id}>
              <span>{v.name}</span>
              <input
                type="radio"
                id={`radio${v.id}`}
                value={v.id}
                checked={currentFilter === v.id}
                onChange={onChangeRadio}
              />
              <label htmlFor={`radio${v.id}`} />
            </div>
          ))}
        </FilterBottom>
      </FilterBox>
    </FilterContainer>
  );
}

0개의 댓글