javascript - 如何在 React 中过滤产品
问题描述
再会,
我是 React 的新手,我正在制作我的第一个电子商务网站。我的问题是:如何按尺寸过滤我的产品?我实在想不出其中的逻辑。预先感谢您的回答。我也尝试过使用 Redux,但没有成功,它给了我以下错误:× TypeError: Cannot read property 'items' of undefined
代码产品卡:
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 }
代码 productReducers:
//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 }
解决方案
过滤器功能正常工作,但我不知道如何应用它。
搜索栏组件:
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
产品成分:
return( // 在渲染产品之前检查加载 loading? loading... : error?{error}:
{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
推荐阅读
- python - 无法获得秘密圣诞老人代码来记住分配的名称
- vmware-fusion - VMware Fusion 12 共享文件夹
- sharepoint-online - 如何确定使用 SharePointOnline 中的 /_vti_bin/listdata.svc 端点创建文档集时发生错误的根本原因?
- wordpress - 如何在自定义 wordpress 页面上添加页面分页?
- php - PHP 8 Match 表达式与 PHP 7 switch case 有什么区别?
- android - 在不同的目录中找不到 Android + JUnit + Espresso 类
- c# - vTiger 7.3.0 使用 CompuMasterGmbH / cammUtils-vTigerNetApi 上传图像
- python - scipy.stats.wasserstein_distance 后面的代码中缺少传输矩阵
- ssl - Python 请求 SSL:TLSV13_ALERT_CERTIFICATE_REQUIRED - 需要 tlsv13 警报证书
- python - 颜色不变