-
아마존 E-commerce 클론 -30) Pagination적용하기NODE.JS 2021. 5. 30. 18:32
먼저 페이지사이즈를 정하고 정해진 수만큼 보여지도록 설정한다.
기능을 추가하기 위해서 백엔드와 프론트엔드 모두 다음과 같은 내용을 추가해준다.
먼저 backend(productRouter.js)
productRouter.get('/' ,expressAsyncHandler(async(req, res)=>{ const pageSize = 3; const page = Number(req.query.pageNumber)||1; const seller = req.query.seller || '' const name = req.query.name || '' const category = req.query.category || '' const min = req.query.min && Number(req.query.min) !== 0? Number(req.query.min):0 const max = req.query.max && Number(req.query.max) !== 0? Number(req.query.max):0 const rating = req.query.rating && Number(req.query.rating) !== 0? Number(req.query.rating):0 const order = req.query.order || '' const sellerFilter = seller? {seller} :{}; const nameFilter = name? {name:{$regex:name, $options:'i'}} :{}; const categoryFilter = category? {category} :{}; const priceFilter = min && max ? {price: {$gte:min, $lte:max}}:{}; const ratingFilter = rating ? {rating: {$gte:rating}}:{}; const sortOrder = order==='lowest'? {price:1} : order==='highest'? {price:-1} : order==='toprated'? {rating:-1} : {_id:-1}; const count = await Product.count({...sellerFilter, ...nameFilter, ...categoryFilter, ...priceFilter, ...ratingFilter}) const products = await Product.find({...sellerFilter, ...nameFilter, ...categoryFilter, ...priceFilter, ...ratingFilter}).populate('seller', 'seller.name seller.logo').sort(sortOrder).skip(pageSize*(page-1)).limit(pageSize); res.send({products, page, pages:Math.ceil(count /pageSize)}); }));
frontend
productactions.js
dispatch({ type:PRODUCT_LIST_REQUEST }); try{ const {data} = await Axios.get(`/api/products?pageNumber=${pageNumber}&seller=${seller}&name=${name}&category=${category}&min=${min}&max=${max}&rating=${rating}&order=${order}`); dispatch({type:PRODUCT_LIST_SUCCESS, payload:data}); }catch(error){ dispatch({type:PRODUCT_LIST_FAIL, payload:error.message}); } } export const detailsProduct = (productId) =>async(dispatch)=>{ dispatch({ type:PRODUCT_DETAILS_REQUEST, payload:productId }); try{ const {data} = await Axios.get(`/api/products/${productId}`); dispatch({type:PRODUCT_DETAILS_SUCCESS, payload:data}) }catch(error){ dispatch({type:PRODUCT_DETAILS_FAIL, payload:error.response && error.response.data.message? error.response.data.message:error.message}) } }
productReducers
export const productListReducer = (state = { loading:true, products: []}, action)=>{ switch(action.type){ case PRODUCT_LIST_REQUEST: return {loading: true}; case PRODUCT_LIST_SUCCESS: return {loading:false, products:action.payload.products, pages:action.payload.pages, page:action.payload.page}; case PRODUCT_LIST_FAIL: return {loading:false, error:action.payload}; default: return state; } }
searchscreen에 페이지를 추가해준다.
const {name = 'all', category='all', min=0, max=0, rating=0, order='newest', pageNumber=1} = useParams(); const productList = useSelector(state => state.productList) const {loading, error, products, page, pages} = productList useEffect(() => { dispatch(listProducts({pageNumber ,name:name!=='all'? name: '', category:category !=='all'? category:'', min, max,rating,order})) }, [category, dispatch,name,min, max,rating,order, pageNumber]) const getFilterUrl = (filter) =>{ const filterPage = filter.page ||pageNumber; const filterCategory = filter.category ||category; const filterName = filter.name ||name; const filterMin = filter.min? filter.min :filter.min===0? 0:min; const filterMax = filter.max? filter.max :filter.max===0? 0:max; const filterRating = filter.rating||rating; const sortOrder = filter.order||order; return `/search/category/${filterCategory}/name/${filterName}/min/${filterMin}/max/${filterMax}/rating/${filterRating}/order/${sortOrder}/pageNumber/${filterPage}` } ... (<> {products.length===0 && <MessageBox>No Product Found</MessageBox>} <div className="row center"> {products.map(product=>( <Product key={product._id} product = {product}/> ))} </div> <div className="row center pagination">//여기에 추가 { [...Array(pages).keys()].map(x=>( <Link key = {x+1} to={getFilterUrl({page:x+1})}>{x+1}</Link> )) } </div> </>)
app.js수정
<Route path="/search/category/:category/name/:name/min/:min/max/:max/rating/:rating/order/:order/pageNumber/:pageNumber" component={SearchScreen} exact></Route>
스타일을 주자
/* Pagenation */ .pagination a{ padding:1rem; margin:0.5rem; border-radius: 0.5rem; border:0.1rem #a4a4a4 solid; font-family: Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }
현재있는 페이지는 스타일을 다르게 주도록 해보자.
<div className="row center pagination"> { [...Array(pages).keys()].map(x=>( <Link classname={x+1===page? 'active':''} key = {x+1} to={getFilterUrl({page:x+1})}>{x+1}</Link> )) } </div>
.pagination a.active{ font-weight: bold; }
이제 products에도 적용시켜보자.
productListScreen.js
import { useParams } from 'react-router'; import {Link} from 'react-router-dom' const {pageNumber=1} = useParams(); //page, pages추가 const {loading, error, products, page, pages}= productList; useEffect(() => { if(successCreate){ dispatch({ type:PRODUCT_CREATE_RESET }) props.history.push(`/product/${createdProduct._id}/edit`) } if(successDelete){ dispatch({type:PRODUCT_DELETE_RESET}) } dispatch(listProducts({pageNumber, seller:sellerMode? userInfo._id :''})) }, [createdProduct, dispatch, props.history, successCreate, successDelete,sellerMode, pageNumber])//pageNumber 바뀌면 다시 실행하기 </table>//테이블 끝나는지점에 추가 <div className="row center pagination"> { [...Array(pages).keys()].map((x)=>( <Link to={`/productlist/pageNumber/${x+1}`} className={x + 1 === page ? 'active' : ''} key = {x+1} >{x+1}</Link> )) } </div> </>
app.js에 루트 추가
<AdminRoute path="/productlist/pageNumber/:pageNumber" component={ProductListScreen} exact></AdminRoute>
추가하고싶다면 order나 다른 페이지에도 추가할 수 있다.
'NODE.JS' 카테고리의 다른 글
아마존 E-commerce 클론 -32) 차트 스크린 만들기 (0) 2021.05.30 아마존 E-commerce 클론 -31) Order Receipt 이메일로 보내기 (0) 2021.05.30 아마존 E-commerce 클론 -29) Google Map적용하기 (0) 2021.05.30 아마존 E-commerce 클론 -28) Rate & Review 생성하기 (0) 2021.05.30 아마존 E-commerce 클론 -27) Search Box ,Search Filter기능 , Side bar, sort & Filter 만들기 (0) 2021.05.29