javascript - 如何防止我的产品列表在父组件购物车状态更新时重新呈现?

标签 javascript reactjs components react-component react-state-management

我有一个 Main.js 组件,它路由到各种组件,包括 Listing.js

  • Main:它包含添加到购物车的产品数组作为状态。

  • 列表:这是产品的列表。它包含数据库中的所有产品。

我的问题:当我通过单击列表组件中的按钮将产品添加到购物车时,它会将产品添加到购物车,并更新状态购物车 主要组件。这样做后,列表组件将重新呈现,并且我会释放访问者在列表中设置的所有过滤器。

我想阻止 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>
        )
    }
}

最佳答案

如果您将匿名函数传递给 Route 中的 component 属性,它每次都会重新渲染。 相反,将您的路线设置为:

<Route path='/listing' render={() => <List addToCart={this.addToCart} />} />

引用react router docs :

When you use component (instead of render or children, below) the router uses React.createElement to create a new React element from the given component. That means if you provide an inline function to the component prop, you would create a new component every render. This results in the existing component unmounting and the new component mounting instead of just updating the existing component. When using an inline function for inline rendering, use the render or the children prop

关于javascript - 如何防止我的产品列表在父组件购物车状态更新时重新呈现?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58646437/

相关文章:

javascript - 了解 Ember.JS itemController

javascript - 扩展 flexbox div,以便在我附加 div 时它可以扩展

javascript - Vue 将新项目添加到对象属性数组中

javascript - 包装一个 VueJs 组件

java - 引用Color变量java改变组件的背景颜色

JSF 组件绑定(bind) - 一些困惑

javascript - asp.net 中的部分粗体文本

javascript - React - onSubmit 表单没有任何数据

javascript - 在react js中哪里声明变量

javascript - "Run the packager with ` --clearCache` 标志在 React Native 中是什么意思?