[Wikea]商品並べ替え機能

40950 ワード

実装機能


  • リストページに出力された商品リストの特定基準の並べ替えが実現された.
  • のデフォルト値は新製品で、低価格、高値、順位、顧客評価、最も人気のある順に具体的な項目を選択することができます.
  • インプリメンテーションコード


    リストデータをdispatchする場合は、オフセット値とカテゴリ名のみを渡す既存のコードに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>
      );
    }