javascript - 反应多个动态路由
问题描述
我正在制作一个产品展示应用程序,它需要在不同级别的分类和产品之间动态路由。
我想出的问题是:
图片(卡片)的前半部分是 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
解决方案
我已经阅读了路由器文档,但我通常不使用复杂的动态参数。
我建议只将产品id
作为路线的参数。通常不需要更复杂的路线。所有其余的产品数据,包括图片 URL,都应该存储在 state 中。
当我在产品视图中时,我希望 ProductList 组件不显示,反之亦然。有没有办法做到这一点?
是的,您应该将产品列表与路由器分开。应该有两个单独的类。呈现产品列表的一种。一种是注册路线并在产品列表和产品详细信息之间进行选择。具体来说,您应该使用<Switch/>
来自react-router
.
推荐阅读
- android - 如何使用 smack 4.3.4 从 android 发送房间配置表单并创建持久性房间
- react-native - 如何在 React Native 中编写格式良好的代码?
- html - 如何创建一个 html 文本编辑器来执行所有语法高亮?
- elasticsearch - ES 节点失败并出现 java.lang.AssertionError: java.text.ParseException
- laravel - 如何激活侧边栏?
- php - 自定义字段ajax搜索
- nativescript - 如何在 natviescript Angular 应用程序中自定义键盘
- swift - Swift CLI:将文本文件(输入)重定向到程序中
- javascript - 我的 keyup 调用 click() 但 click() 不委托
- mysql - DBMS 似乎要提交中间事务(新手问题)