如何在React中过滤产品

问题描述 投票:0回答:3

美好的一天,

我是 React 的新手,我正在制作我的第一个电子商务网站。我的问题是:如何按尺寸过滤我的产品?我实在想不出其中的逻辑。预先感谢您的回答。我也尝试过使用 Redux,但没有成功,它给了我以下错误:× 类型错误:无法读取未定义的属性“项目”

代码产品卡:

import React,{useState,useEffect} from 'react'
import {Link} from 'react-router-dom'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import {Library} from '@fortawesome/fontawesome-svg-core'
import {faShoppingBasket} from '@fortawesome/free-solid-svg-icons'
import {useDispatch, useSelector} from 'react-redux'
import { listProduct, Filterproducts } from '../../actions/productActions'



function Product(props){
    //default value is an array, because we've got data in an array 
    const [qty,setQty] = useState(1)
    const productList = useSelector(state=>state.productList)
    const{products,loading,error}=productList
    const dispatch = useDispatch()
    
    // handlefilter

  

    useEffect(()=> {
        dispatch(listProduct())
       


  

    }, [])

    // handle cart adding
    const handleAddToCart = ()=> {
        props.history.push('/cart/' + props.match.params.id +  "?qty" +qty)
    }


  


   
    return( 
        // Check the loading before rendering products
        loading? <div><h1 className="load">loading...</h1></div> : 
        error?<div>{error}</div>:
           <ul className="products">
               
            {products.map(product=> (
        
            <li key={product.id} className="product"> 
             <Link to={"/product/" + product.id}><div className="img" style={{background: `url(${product.img})`, backgroundSize: 'cover'}}></div></Link>
                   {/* LOOK OUT FOR TYPOS IN ROUTIING  dont put':' after /, this only applies
                   when routing because the ": " implies for a parameter
                   In this case you can directly access product.id  */}
               <Link to={"/product/" +  product.id}><h1>{product.name}</h1></Link> 
                <p> <small>€</small>{product.price}</p>
                <div>size: {product.size}</div>
              
                {product.qty > 0 ? <div><button onClick={handleAddToCart}>Add to cart</button>  <div>{product.qty} left</div></div> : <div>out of stock</div> }   
               
             
                
                </li> 
                )
                
                )}
   
                 </ul>
                 
       
    
    )
}
export default Product

产品操作代码:

import Axios from 'axios'
import {
    PRODUCT_LIST_FAIL, 
    PRODUCT_LIST_REQUEST, 
    PRODUCT_LIST_SUCCESS, 
    PRODUCT_DETAILS_REQUEST,
    PRODUCT_DETAILS_SUCCESS,
    PRODUCT_DETAILS_FAIL,
    FILTER_PRODUCTS_BY_PRICE,
    FILTER_PRODUCTS_BY_SIZE} from '../constants/productConstants'



const listProduct = () => async(dispatch)=> {
    
        try{
            dispatch({type:PRODUCT_LIST_REQUEST})
            fetch('http://localhost:5000/')
            .then(res=> res.json())
            .then(data=> dispatch({type: PRODUCT_LIST_SUCCESS, payload:data}) )
           
        }
        catch(error){
            dispatch({type: PRODUCT_LIST_FAIL, payload:error.message})
        }
   
  
  
}
// DETAILSPRODUCT
//we need to have a server in order to display the products
//it should get another link which contains the id of the product
const detailsProduct = (productId) => async(dispatch) => {
    try{
        dispatch({type: PRODUCT_DETAILS_REQUEST, payload: productId});
        fetch('http://localhost:5000/' + productId)
        .then(res=> res.json())
        .then(data=> dispatch({type: PRODUCT_DETAILS_SUCCESS, payload:data}) )
    }
    catch(error){
        dispatch({type: PRODUCT_DETAILS_FAIL, payload: error.message})
    }
}

// Filter products
const Filterproducts = (products,size) => (dispatch) => {
    return dispatch({
        type:FILTER_PRODUCTS_BY_SIZE,
        payload: {
            size:size,
            items:size === '' ? products : products.filter(a=> a.indexOf(size.toUpperCase()) >= 0)
        }
    })
}


export { listProduct, detailsProduct, Filterproducts }

代码产品减速器:

//two params are being accepted in the reducer func
    //* state 

import { 
    PRODUCT_DETAILS_FAIL,
    PRODUCT_DETAILS_REQUEST,
    PRODUCT_DETAILS_SUCCESS, 
    PRODUCT_LIST_FAIL, 
    PRODUCT_LIST_REQUEST, 
    PRODUCT_LIST_SUCCESS,
    FILTER_PRODUCTS_BY_SIZE,
    FILTER_PRODUCTS_BY_PRICE } from "../constants/productConstants";

    //*action
function producListReducer(state = {products: [], filteredItems: [], size: ''}, action){
    
    switch (action.type){
        // case is like the if statement
        //getting product
        case PRODUCT_LIST_REQUEST:
            return{loading: true};
            // when products are loaded
        case PRODUCT_LIST_SUCCESS:
            return{loading:false, products: action.payload};
            //when err occurs
        case PRODUCT_LIST_FAIL:
            return{loading: false, error: action.payload};
        case FILTER_PRODUCTS_BY_SIZE:
                return{...state, filteredItems: action.payload.items, size: action.payload.size}
        default:
                return state
    }
}

function productDetailsReducer(state = {product: {}}, action){
    
    switch (action.type){
        // case is like the if statement
        //getting product
        case PRODUCT_DETAILS_REQUEST:
            return{loading: true};
            // when products are loaded
        case PRODUCT_DETAILS_SUCCESS:
            return{loading:false, product: action.payload};
            //when err occurs
        case PRODUCT_DETAILS_FAIL:
            return{loading: false, error: action.payload};
        default:
                return state
    }
}







export { producListReducer,productDetailsReducer }
javascript node.js reactjs redux
3个回答
0
投票

错误消息意味着您正在尝试访问不存在的对象的关键“项目”。在发布的代码中唯一执行此操作的是在productReducers中,因此我建议您检查返回有效负载的函数“Filterproducts”。


0
投票

过滤功能可以工作,但我不知道如何应用它。

搜索栏组件:

import React from 'react'


// Function Searchbar 
//Looks for products 

function Search(props){

   
    return(
     <input 
     type="search"
     className="search"
     placeholder={props.placeholder}
     onChange={props.handleInput}/>
    )
}

export default Search

产品成分:

返回( // 在渲染产品之前检查加载情况 加载中?加载中... : 错误?{错误}:

    {products.map(product=> (
    
        

    <li key={product.id} className="product"> 
     <Link to={"/product/" + product.id}><div className="img" style={{background: `url(${product.img})`, backgroundSize: 'cover'}}></div></Link>
           {/* LOOK OUT FOR TYPOS IN ROUTIING  dont put':' after /, this only applies
           when routing because the ": " implies for a parameter
           In this case you can directly access product.id  */}
       <Link to={"/product/" +  product.id}><h1>{product.name}</h1></Link> 
        <p> <small>€</small>{product.price}</p>
        <div>size: {product.size}</div>
      
        {product.qty > 0 ? <div><button onClick={handleAddToCart}>Add to cart</button>  <div>{product.qty} left</div></div> : <div>out of stock</div> }   
       
     
        
        </li> 
        )
        
        )}

         </ul>
        
         

Store.js 中的搜索栏功能:

import React,{Component, useState} from 'react'
import Product from '../components/product'
import Nav from '../components/nav'
import Footer from '../components/footer'
import Searchbar from '../components/searchbar'
import Filter from '../components/filter'


class Store extends Component{
   
    constructor(){
        super()
        this.state = {
            products: [],
            SearchProduct: ''
        }
    }
    componentDidMount(){
        fetch('http://localhost:5000/')
        .then(res=> res.json())
        .then(data=>this.setState({products:data}) )
       
    }
   
   render(){
       let filteredProducts = this.state.products.filter((product)=> {
            return product.name.toLowerCase().includes(this.state.SearchProduct.toLowerCase())
       })
    return (
        
        <div>
        <Nav/>
        <div className="store">

           
            <div className="title">
                <h1>Store</h1>
            </div>
            <aside>
                <Searchbar 
                placeholder="Search" 
                handleInput={(e)=> {
                   
                    this.setState({SearchProduct: e.target.value})
                }
                 
                } 
                />
                
                <ul>
                    <h2>Categories</h2>
                    <li>Women</li>
                    <li>Men</li>
                    <li>Clothing</li>
                    <li>Equipment</li>
                 
                </ul>
            </aside>
           
           <Filter/>
            
            <Product filter={filteredProducts}/>
            
         
           
        </div>
        <Footer/>
        </div>
    )
   }
   
}

export default Store

0
投票

这里是应用价格、类别、排序和分页等过滤器的示例

const getPaginatedProducts = products
    .slice(startIndex, endIndex)
    .filter(item => {
        if (categoryData !== "") {
            if (item.category !== categoryData) return false;
        }
        if (price.min && price.max) {
            if (item.sale_price < price.min || item.sale_price > price.max) return false;
        } else {
            if (price.min && item.sale_price < price.min) return false;
            if (price.max && item.sale_price > price.max) return false;
        }
        return true;
    })
    .sort((a, b) => {
        switch (sort) {
            case "highToLow":
                return comparePrices(b, a);
            case "lowToHigh":
                return comparePrices(a, b);
            case "popular":
                return b.top - a.top;
            case "new":
                return b.id - a.id;
            default:
                return 0;
        }
    });

//sort
const comparePrices = (a, b) => {
    return a.sale_price - b.sale_price;
};

使用添加分页

showLimit = 10,
showPagination = 4;

let [pagination, setPagination] = useState([]);
let [limit, setLimit] = useState(showLimit);
let [pages, setPages] = useState(Math.ceil(products.length / limit));
let [currentPage, setCurrentPage] = useState(1);

const cratePagination = () => {
    // set pagination
    let arr = new Array(Math.ceil(products.length / limit))
        .fill()
        .map((_, idx) => idx + 1);

    setPagination(arr);
    setPages(Math.ceil(products.length / limit));
};

const startIndex = currentPage * limit - limit;
const endIndex = startIndex + limit;




<Pagination
    getPaginationGroup={
        getPaginationGroup
    }
    currentPage={currentPage}
    pages={pages}
    next={next}
    prev={prev}
    handleActive={handleActive}
/>






function Pagination({
    prev,
    currentPage,
    getPaginationGroup,
    next,
    pages,
    handleActive,
}) {
    return (
        <>
            <ul className="pagination justify-content-start">
                {getPaginationGroup.length <= 0 ? null : (
                    <li onClick={prev} className="page-item">
                        {currentPage === 1 ? null : (
                            <a className="page-link">
                                <i className="fi-rs-angle-double-small-left"></i>
                            </a>
                        )}
                    </li>
                )}

                {getPaginationGroup.map((item, index) => {
                    return (
                        <li
                            onClick={() => handleActive(item)}
                            key={index}
                            className={
                                currentPage === item
                                    ? "page-item active"
                                    : "page-item"
                            }
                        >
                            <a className="page-link">{item}</a>
                        </li>
                    );
                })}

                {getPaginationGroup.length <= 0 ? null : (
                    <li onClick={next} className="page-item">
                        {currentPage >= pages ? null : (
                            <a className="page-link">
                                <i className="fi-rs-angle-double-small-right"></i>
                            </a>
                        )}
                    </li>
                )}
            </ul>

            {getPaginationGroup.length <= 0 ? null : (
                <p>
                    show {currentPage} of {pages}
                </p>
            )}
        </>
    );
}
© www.soinside.com 2019 - 2024. All rights reserved.