我正在制作一个产品展示应用程序,该应用程序需要在不同级别的分类和产品之间动态路由。
我要提出的问题是:
图片的上半部分(卡)是ProductList组件。后半部分是产品组件。
import React, { Component } from "react";
import { BrowserRouter, NavLink, Route } from "react-router-dom";
import Card from "@material-ui/core/Card";
import CardActionArea from "@material-ui/core/CardActionArea";
import CardContent from "@material-ui/core/CardContent";
import CardMedia from "@material-ui/core/CardMedia";
import Typography from "@material-ui/core/Typography";
import equal from "fast-deep-equal";
import "./ProductList.scss";
import Product from "./Product";
const products = [
{
barcode: "8434786605357",
collection: "2019",
colorCode: "0",
colorName: "DENIM",
familyName: "Denim Pants",
genericProduct: "PM200338WV7",
id: 263934,
image: [
"http://tools.bexfyinfra.com/bexfy-touch-app-test/PM200338WV7/PM200338WV7_000_01_MO.jpg",
"http://tools.bexfyinfra.com/bexfy-touch-app-test/PM200338WV7/PM200338WV7_000_02_MO.jpg",
"http://tools.bexfyinfra.com/bexfy-touch-app-test/PM200338WV7/PM200338WV7_000_03_MO.jpg"
],
line: "Men",
productCode: "PM200338WV7000040",
productName: "FINSBURY SKINNY FIT LOW WAIST JEANS",
productNameLang: "en",
season: "AW",
size: "40",
subfamilyName: "Jeans"
},
{
barcode: ["8434786289854", "8434786289847", "8434786289861"],
collection: "2019",
colorCode: "0AA",
colorName: "MULTI",
familyName: "Dresses",
genericProduct: "PL952477",
id: [263935, 263938, 263939],
image: [
"http://tools.bexfyinfra.com/bexfy-touch-app-test/PL952477/PL952477_0AA_01_MO.jpg",
"http://tools.bexfyinfra.com/bexfy-touch-app-test/PL952477/PL952477_0AA_02_MO.jpg",
"http://tools.bexfyinfra.com/bexfy-touch-app-test/PL952477/PL952477_0AA_03_MO.jpg",
"http://tools.bexfyinfra.com/bexfy-touch-app-test/PL952477/PL952477_0AA_01_MO.jpg",
"http://tools.bexfyinfra.com/bexfy-touch-app-test/PL952477/PL952477_0AA_02_MO.jpg",
"http://tools.bexfyinfra.com/bexfy-touch-app-test/PL952477/PL952477_0AA_03_MO.jpg",
"http://tools.bexfyinfra.com/bexfy-touch-app-test/PL952477/PL952477_0AA_01_MO.jpg",
"http://tools.bexfyinfra.com/bexfy-touch-app-test/PL952477/PL952477_0AA_02_MO.jpg",
"http://tools.bexfyinfra.com/bexfy-touch-app-test/PL952477/PL952477_0AA_03_MO.jpg"
],
line: "Women",
productCode: ["PL9524770AAM", "PL9524770AAL", "PL9524770AAS"],
productName: "FIONA CROSSOVER DRESS",
productNameLang: "en",
season: "SS",
size: ["M", "L", "S"],
subfamilyName: "Dresses NS/SS"
},
{
barcode: "8434786258508",
collection: "2019",
colorCode: "599",
colorName: "NACHT",
familyName: "Swimwear",
genericProduct: "PMB10211",
id: 263936,
image: [
"http://tools.bexfyinfra.com/bexfy-touch-app-test/PMB10211/PMB10211_599_01_MO.jpg",
"http://tools.bexfyinfra.com/bexfy-touch-app-test/PMB10211/PMB10211_599_02_MO.jpg",
"http://tools.bexfyinfra.com/bexfy-touch-app-test/PMB10211/PMB10211_599_03_MO.jpg"
],
line: "Men",
productCode: "PMB10211599XL",
productName: "ALMONTE SHORT SWIMSUIT",
productNameLang: "en",
season: "SS",
size: "XL",
subfamilyName: "Swimsuits"
}
];
const productCategories = [
{
grandparent: null,
level: 1,
name: "Men",
parent: null,
path: "/men"
},
{
grandparent: null,
level: 2,
name: "Denim Pants",
parent: "Men",
path: "/men/denim-pants"
},
{
grandparent: "Men",
level: 3,
name: "Jeans",
parent: "Denim Pants",
path: "/men/denim-pants/jeans"
},
{
grandparent: null,
level: 1,
name: "Women",
parent: null,
path: "/women"
},
{
grandparent: null,
level: 2,
name: "Dresses",
parent: "Women",
path: "/women/dresses"
},
{
grandparent: "Women",
level: 3,
name: "Dresses NS/SS",
parent: "Dresses",
path: "/women/dresses/dresses-ns-ss"
},
{
grandparent: null,
level: 2,
name: "Swimwear",
parent: "Men",
path: "/men/swimwear"
},
{
grandparent: "Men",
level: 3,
name: "Swimsuits",
parent: "Swimwear",
path: "/men/swimwear/swimsuits"
},
{
grandparent: null,
level: 2,
name: "T-Shirts",
parent: "Men",
path: "/men/t-shirts"
},
{
grandparent: "Men",
level: 3,
name: "SS T-Shirts",
parent: "T-Shirts",
path: "/men/t-shirts/ss-t-shirts"
},
{
name: "T-Shirts",
path: "/women/t-shirts",
parent: "Women",
grandparent: null,
level: 2
},
{
grandparent: "Women",
level: 3,
name: "SS T-Shirts",
parent: "T-Shirts",
path: "/women/t-shirts/ss-t-shirts"
}
];
class ProductList extends Component {
constructor(props) {
super(props);
this.state = {
filteredProducts: []
};
}
componentDidUpdate(prevProps) {
if (!equal(this.props, prevProps)) {
this.filterProducts();
}
}
filterProducts() {
let productsFiltered = null;
console.log(products);
if (this.props.match.params.subfamily !== undefined) {
productsFiltered = products
.filter(
product =>
product.line
.toLowerCase()
.replace(/\s+/g, "-")
.replace(/\//g, "-") === this.props.match.params.line
)
.filter(
product =>
product.familyName
.toLowerCase()
.replace(/\s+/g, "-")
.replace(/\//g, "-") === this.props.match.params.family
)
.filter(
product =>
product.subfamilyName
.toLowerCase()
.replace(/\s+/g, "-")
.replace(/\//g, "-") === this.props.match.params.subfamily
);
} else if (this.props.match.params.family !== undefined) {
productsFiltered = products
.filter(
product =>
product.line
.toLowerCase()
.replace(/\s+/g, "-")
.replace(/\//g, "-") === this.props.match.params.line
)
.filter(
product =>
product.familyName
.toLowerCase()
.replace(/\s+/g, "-")
.replace(/\//g, "-") === this.props.match.params.family
);
} else {
productsFiltered = products.filter(
product =>
product.line
.toLowerCase()
.replace(/\s+/g, "-")
.replace(/\//g, "-") === this.props.match.params.line
);
}
this.setState({
filteredProducts: productsFiltered
});
}
render() {
return (
<BrowserRouter>
<div className="product-cards">
{this.state.filteredProducts.map(product => (
<Card
key={product.id}
className={product.productName + " card"}
style={{ maxWidth: 145, margin: 10 }}
>
<CardActionArea>
<NavLink to={`/${product.id}`}>
<CardMedia
component="img"
alt="Product Image"
height="240"
image={product.image[0]}
title={product.productName}
/>
<CardContent>
<Typography
gutterBottom
variant="h5"
component="p"
style={{ fontSize: ".8rem" }}
>
{product.productName}
</Typography>
</CardContent>
</NavLink>
</CardActionArea>
</Card>
))}
</div>
<Route exact path={`/:product`} component={Product} />
</BrowserRouter>
);
}
}
export default ProductList;
import React, { Component } from "react";
import equal from "fast-deep-equal";
import ImageGallery from "react-image-gallery";
import MenuItem from "@material-ui/core/MenuItem";
import FormControl from "@material-ui/core/FormControl";
import Select from "@material-ui/core/Select";
import "./Product.scss";
const productList = [
{
barcode: "8434786605357",
collection: "2019",
colorCode: "0",
colorName: "DENIM",
familyName: "Denim Pants",
genericProduct: "PM200338WV7",
id: 263934,
image: [
"http://tools.bexfyinfra.com/bexfy-touch-app-test/PM200338WV7/PM200338WV7_000_01_MO.jpg",
"http://tools.bexfyinfra.com/bexfy-touch-app-test/PM200338WV7/PM200338WV7_000_02_MO.jpg",
"http://tools.bexfyinfra.com/bexfy-touch-app-test/PM200338WV7/PM200338WV7_000_03_MO.jpg"
],
line: "Men",
productCode: "PM200338WV7000040",
productName: "FINSBURY SKINNY FIT LOW WAIST JEANS",
productNameLang: "en",
season: "AW",
size: "40",
subfamilyName: "Jeans"
},
{
barcode: ["8434786289854", "8434786289847", "8434786289861"],
collection: "2019",
colorCode: "0AA",
colorName: "MULTI",
familyName: "Dresses",
genericProduct: "PL952477",
id: [263935, 263938, 263939],
image: [
"http://tools.bexfyinfra.com/bexfy-touch-app-test/PL952477/PL952477_0AA_01_MO.jpg",
"http://tools.bexfyinfra.com/bexfy-touch-app-test/PL952477/PL952477_0AA_02_MO.jpg",
"http://tools.bexfyinfra.com/bexfy-touch-app-test/PL952477/PL952477_0AA_03_MO.jpg",
"http://tools.bexfyinfra.com/bexfy-touch-app-test/PL952477/PL952477_0AA_01_MO.jpg",
"http://tools.bexfyinfra.com/bexfy-touch-app-test/PL952477/PL952477_0AA_02_MO.jpg",
"http://tools.bexfyinfra.com/bexfy-touch-app-test/PL952477/PL952477_0AA_03_MO.jpg",
"http://tools.bexfyinfra.com/bexfy-touch-app-test/PL952477/PL952477_0AA_01_MO.jpg",
"http://tools.bexfyinfra.com/bexfy-touch-app-test/PL952477/PL952477_0AA_02_MO.jpg",
"http://tools.bexfyinfra.com/bexfy-touch-app-test/PL952477/PL952477_0AA_03_MO.jpg"
],
line: "Women",
productCode: ["PL9524770AAM", "PL9524770AAL", "PL9524770AAS"],
productName: "FIONA CROSSOVER DRESS",
productNameLang: "en",
season: "SS",
size: ["M", "L", "S"],
subfamilyName: "Dresses NS/SS"
},
{
barcode: "8434786258508",
collection: "2019",
colorCode: "599",
colorName: "NACHT",
familyName: "Swimwear",
genericProduct: "PMB10211",
id: 263936,
image: [
"http://tools.bexfyinfra.com/bexfy-touch-app-test/PMB10211/PMB10211_599_01_MO.jpg",
"http://tools.bexfyinfra.com/bexfy-touch-app-test/PMB10211/PMB10211_599_02_MO.jpg",
"http://tools.bexfyinfra.com/bexfy-touch-app-test/PMB10211/PMB10211_599_03_MO.jpg"
],
line: "Men",
productCode: "PMB10211599XL",
productName: "ALMONTE SHORT SWIMSUIT",
productNameLang: "en",
season: "SS",
size: "XL",
subfamilyName: "Swimsuits"
}
];
class Product extends Component {
constructor(props) {
super(props);
this.state = {
product: null,
images: [
{
original: "https://picsum.photos/id/1018/1000/600/",
thumbnail: "https://picsum.photos/id/1018/250/150/"
},
{
original: "https://picsum.photos/id/1015/1000/600/",
thumbnail: "https://picsum.photos/id/1015/250/150/"
},
{
original: "https://picsum.photos/id/1019/1000/600/",
thumbnail: "https://picsum.photos/id/1019/250/150/"
}
]
};
}
componentDidUpdate(prevProps) {
if (!equal(this.props, prevProps)) {
this.filterProduct();
}
}
filterProduct() {
let productId = this.props.match.params.product;
console.log(productId);
let selectedProduct = productList.filter(
product => product.id == productId
);
console.log(selectedProduct);
let images = selectedProduct[0].image.map(img => {
return { original: img, thumbnail: img };
});
console.log(productId);
console.log(this.state);
this.setState({
product: selectedProduct,
images: images
});
}
handleChangeSize = event => {
this.setState({ selectedSize: event.target.value });
};
handleChangeColor = event => {
this.setState({ selectedColor: event.target.value });
};
render() {
return (
<div>
{this.state.product !== null && (
<>
<ImageGallery items={this.state.images} thumbnailPosition="left" />
<div className="product-description">
<h3>{this.state.product[0].productName}</h3>
<h5>
{Array.isArray(this.state.product[0].productCode)
? this.state.product[0].productCode[0]
: this.state.product[0].productCode}
</h5>
{Array.isArray(this.state.product[0].size) ? (
<form
styles={{
display: "flex",
flexWrap: "wrap"
}}
>
<FormControl styles={{ minWidth: 120 }}>
<span className="product-label">Size:</span>
<Select
value={this.state.selectedSize}
onChange={this.handleChangeSize}
>
{this.state.product[0].size.map((item, index) => {
return (
<MenuItem
key={index}
value={this.state.product[0].size[index]}
>
{this.state.product[0].size[index]}
</MenuItem>
);
})}
</Select>
</FormControl>
</form>
) : (
<div>
<span className="product-label">Size:</span>
{this.state.product[0].size}
</div>
)}
{Array.isArray(this.state.product[0].colorCode) ? (
<form
styles={{
display: "flex",
flexWrap: "wrap"
}}
>
<FormControl styles={{ minWidth: 120 }}>
<span className="product-label">Color:</span>
<Select
value={this.state.selectedColor}
onChange={this.handleChangeColor}
>
{this.state.product[0].colorCode.map((item, index) => {
return (
<MenuItem
key={index}
value={this.state.product[0].colorCode[index]}
>
{this.state.product[0].colorName[index]}
</MenuItem>
);
})}
</Select>
</FormControl>
</form>
) : (
<div>
<span className="product-label">Color:</span>
{this.state.product[0].colorName}
</div>
)}
</div>
</>
)}
</div>
);
}
}
export default Product;
我已阅读路由器文档,但通常不使用复杂的动态参数。我可以使用该路线的“精确”道具解决类似的问题,但是它不能动态生成。
我希望在产品视图中不显示ProductList组件,反之亦然。有办法吗?
实现此目标的最佳方法是什么?
CodeSandbox游乐场:https://codesandbox.io/s/musing-firefly-tm9r0?fontsize=14
答案 0 :(得分:0)
我已阅读路由器文档,但通常不使用复杂的动态参数。
我建议仅提供产品id
作为路由的参数。通常不需要更复杂的路线。产品的所有其他剩余数据,包括图像URL,都应按状态存储。
我希望在产品视图中不显示ProductList组件,反之亦然。有办法吗?
是的,您应该将产品列表与路由器分开。应该有两个单独的类。呈现产品列表的一个。并注册路线并在产品列表和产品详细信息之间进行选择。具体来说,您应该使用<Switch/>
中的react-router
组件。