javascript - 如何防止我的产品列表在父组件购物车状态更新时重新呈现?
问题描述
我有一个Main.js组件,该组件路由到各种组件,包括Listing.js。
Main:它包含作为状态的一组添加到购物车的产品。
清单:这是产品的清单。它包含数据库中的所有产品作为状态。
我的问题:当我通过单击 List 组件中的按钮将产品添加到购物车时,它会将产品添加到购物车,从而更新Main组件的状态购物车。这样做,List组件会重新呈现,并且我会丢失访问者在列表中设置的所有过滤器。
我想防止 List 在其父组件的购物车状态发生更改时重新呈现。你知道怎么做吗?我已经尝试过 shouldComponentUpdate,但没有成功。
Main.js(父组件)
import React from 'react';
import {Switch, Route, withRouter, Link} from "react-router-dom";
import {List} from "./Listing/List";
class Main extends React.Component
{
state={
cart:[],
};
removeFromCart = product => //REMOVES PRODUCT FROM CART
{
let cart = this.state.cart;
cart.map(item => {
if(item._id === product._id)
{
item.count--;
return item;
}
});
cart = cart.filter(item => item.count > 0);
this.setState({cart:cart}, () => {sessionStorage.setItem('cart', JSON.stringify(cart));});
};
addToCart = product => //ADD PRODUCT TO CART
{
let cart = this.state.cart;
let productExists = this.state.cart.map(item => {return item._id === product._id}).includes(true);
if(productExists)
{
cart = cart.map(item => {
if(item._id === product._id)
{
item.count++;
return item;
}
else
{
return item;
}
});
}
else
{
product.count = 1;
cart.push(product);
}
this.setState({cart: cart}, () => {sessionStorage.setItem('cart', JSON.stringify(cart));});
};
componentWillMount()
{
if(sessionStorage.getItem('cart')) this.setState({cart:JSON.parse(sessionStorage.getItem('cart'))});
}
render() {
return (
<div className='main'>
<Header cart={this.state.cart} />
<Switch>
<Route path='/listing' component={() => <List addToCart={this.addToCart} />} />
</Switch>
</div>
);
}
}
export default withRouter(Main);
List.js,产品列表:
import React from "react";
import {Product} from "./Product";
import Data from '../../Utils/Data';
import {Search} from "./Search/Search";
export class List extends React.Component
{
state = {
serie: '',
products: [],
filteredProducts: [],
};
addToCart = this.props.addToCart;
obtainProducts = (request = {}) => //searches for products in database
{
Data.products.obtain(request).then(products => {
this.setState({products:products, filteredProducts: products});
});
};
displayProducts = () => {
//Only products that has title
const products = this.state.filteredProducts.filter(product => {return product.title;});
//Returns REACT COMPONENT
return products.map(product => {
return <Product
key={product._id}
product={product}
addToCart={this.addToCart}
/>
});
};
searchHandler = (collection, types) =>
{
let filteredProducts = this.state.products;
if(collection.length)
filteredProducts = filteredProducts.filter(product => {return collection.includes(product.series);});
if(types.length)
filteredProducts = filteredProducts.filter(product => {return types.includes(product.type);});
this.setState({filteredProducts: filteredProducts});
};
componentWillMount()
{
//init products collection
this.obtainProducts();
}
render()
{
const productComponents = this.displayProducts();
console.log('test');
return(
<section className='listing'>
<Search searchHandler={this.searchHandler} />
<div className='listing-content grid-4 has-gutter'>
{productComponents}
</div>
</section>
)
}
}
解决方案
如果您将匿名函数传递给component
Route 中的 prop,则它每次都会重新渲染。相反,将您的路线设置为:
<Route path='/listing' render={() => <List addToCart={this.addToCart} />} />
引用反应路由器文档:
当你使用组件(而不是渲染或子,下面)时,路由器使用 React.createElement 从给定组件创建一个新的 React 元素。这意味着如果您为组件属性提供内联函数,您将在每次渲染时创建一个新组件。这会导致现有组件卸载和新组件安装,而不是仅仅更新现有组件。当使用内联函数进行内联渲染时,使用 render 或 children 属性
推荐阅读
- composer-php - 为什么推荐的带有 Composer 的 Drupal 安装方法使用 dev 作为稳定性标志?
- php - 在 null zendframework 3 上调用成员函数 hello()
- vue.js - Vue - 单个文件组件中的翻译
- ios - 我可以控制 concurrentPerform 的并行性吗?
- javascript - javascript 从字符串中提取主题标签
- ghost-blog - 幽灵到媒体的整合
- java - 如何在 Javafx 中删除视频开头的主窗口闪烁?
- python - 在键级python下面的字典中添加新元素
- xslt - xslt 多个插入节点(如果不存在)
- c# - Swashbuckle 在 asp.net 核心中失败,出现 NotSupportedException 异常