首页 > 解决方案 > Reactjs 更新状态而不重新加载页面

问题描述

我在我的应用程序中构建了一个购物车。这是流程:
- 客户看到一个项目列表并点击他想要的一个;
- 下一页是他选择产品数量的地方,然后我保存在localStorage中;
- 通过点击确认,他会带着他选择的相同产品进入购物车。在此页面(购物车)上,他可以更改数量,此时总数和数量必须更改(见图)。
我能够重新加载页面,但是在生产中页面无法正常工作。我需要在不重新加载页面的情况下执行此操作。
如何在不重新加载页面的情况下执行此操作?
我有 3 个组件:标题(带有图标购物车)、ChooseQuantity 和购物车。
见下面的代码:
在此处输入图像描述

//My Choose Quantity Component
import React from 'react';
import '../../components/ChooseQuantity/ChooseQuantity.css';

class ChooseQuantity extends React.Component {

    constructor(props) {
        super(props);
        const { lotQuantity, totalQuantity, maxTotalItems, maxPurchase, lot, totalTickets, events, onChange } = this.props;
        this.state = {
            counter: 0,
            lotQuantity: lotQuantity,
            totalQuantity: totalQuantity,
            maxTotalItems: maxTotalItems,
            maxPurchase: maxPurchase,
            totalTickets: totalTickets,
            onChange: onChange,
            events: events,
            lot: lot,
            tickets: events.tickets,
            cart: []

        }
        this.increment = this.increment.bind(this);
        this.decrement = this.decrement.bind(this);
    }

    componentDidMount() {
        // console.log(this.state.lot);
        // localStorage.setItem('teste', JSON.stringify(this.state.lotQuantity));
    }

    // static getDerivedStateFromProps(props, state) {
    //     console.log(props.lot);
    //     // console.log(state);
    //     if (props.selected !== state.selected) {
    //         return {
    //             selected: props.selected,
    //         };
    //     }
    // }

    // componentDidUpdate(prevProps, prevState) {
    //     console.log(this.props.lot);
    //     localStorage.setItem('teste', JSON.stringify(this.props.lot.quantity));
    //     if (this.props.lot !== prevProps.lot) {
    //         // this.selectNew();
    //     }
    // }

    async increment() {
        await this.setState({
            lotQuantity: this.state.lotQuantity + 1,
            totalQuantity: + 1,
        });
        let lotUniqueNumber = this.state.lot.lotUniqueNumber;
        let lotQuantity = this.state.lotQuantity;
        var ar_lot = [];
        this.state.tickets.lot.forEach(function (item) {
            if (lotUniqueNumber === item.lotUniqueNumber) {
                item.quantity = lotQuantity;
                item.total = item.totalLotPrice * item.quantity
            }
            ar_lot.push(item);
        })
        // console.log(ar_lot);

        //CALCULATING A QUANTITY
        var ob_qtd = ar_lot.reduce(function (prevVal, elem) {
            const ob_qtd = prevVal + elem.quantity;
            return ob_qtd;
        }, 0);
        await this.setState({ totalTickets: ob_qtd })
        //CALCULATING A QUANTITY

        //CALCULATING THE TOTAL
        var ob_total = ar_lot.reduce(function (prevVal, elem) {
            const ob_total = prevVal + elem.total;
            return ob_total;
        }, 0);
        // CALCULATING THE TOTAL

        //RIDING THE SHOPPING CART
        let total = {
            price: ob_total,
            totalQuantity: ob_qtd,
        };

        let tickets = {
            name: this.state.tickets.name,
            prevenda: this.state.tickets.prevenda,
            unique_number: this.state.tickets.unique_number,
            lot: ar_lot
        }
        let events = {
            banner_app: this.state.events.banner_app,
            installments: this.state.events.installments,
            max_purchase: this.state.events.max_purchase,
            name: this.state.events.name,
            tickets: tickets
        }
        var cart = { events: events, total: total };
        this.setState({
            cart: cart
        })
        // console.log(cart);
        localStorage.setItem('cart', JSON.stringify(cart));//RECORDING CART IN LOCALSTORAGE
        localStorage.setItem('qtd', JSON.stringify(ob_qtd));
        window.location.reload();//UPDATE PAGE FOR CHANGES TO BE UPDATED
    }

    async decrement() {
        await this.setState({
            lotQuantity: this.state.lotQuantity - 1,
            totalQuantity: - 1,
            totalTickets: this.state.totalTickets - 1,
        });

        let lotUniqueNumber = this.state.lot.lotUniqueNumber;

        let lotQuantity = this.state.lotQuantity;
        var ar_lot = [];
        this.state.tickets.lot.forEach(function (item) {
            if (lotUniqueNumber === item.lotUniqueNumber) {
                item.quantity = lotQuantity;
                item.total = item.totalLotPrice * item.quantity
            }
            ar_lot.push(item);
        })

        //CALCULANDO A QUANTIDADE
        var ob_qtd = ar_lot.reduce(function (prevVal, elem) {
            const ob_qtd = prevVal + elem.quantity;
            return ob_qtd;
        }, 0);
        //CALCULANDO A QUANTIDADE

        //CALCULANDO O TOTAL
        var ob_total = ar_lot.reduce(function (prevVal, elem) {
            const ob_total = prevVal + elem.total;
            return ob_total;
        }, 0);
        //CALCULANDO O TOTAL

        let total = {
            price: ob_total,
            totalQuantity: ob_qtd,
        };

        let tickets = {
            name: this.state.tickets.name,
            prevenda: this.state.tickets.prevenda,
            unique_number: this.state.tickets.unique_number,
            lot: ar_lot
        }
        let events = {
            banner_app: this.state.events.banner_app,
            installments: this.state.events.installments,
            max_purchase: this.state.events.max_purchase,
            name: this.state.events.name,
            tickets: tickets
        }
        var cart = { events: events, total: total };
        localStorage.setItem('cart', JSON.stringify(cart));
        localStorage.setItem('qtd', JSON.stringify(ob_qtd));
        window.location.reload();
    }

    render() {
        return (
            <div className="choose-quantity">
                {
                    this.state.lotQuantity <= 0 ?
                        <div className="space-button"></div> :
                        <button className='minus' onClick={this.decrement}><i className="fas fa-minus"></i></button>
                }
                <div id='counter' className="qtd" value={this.state.lotQuantity} onChange={this.onChange}>{this.state.lotQuantity}</div>
                {
                    this.state.totalTickets >= this.state.maxPurchase ?
                        <div className="space-button"></div> :
                        <button className="plus" onClick={() => this.increment(this.state.lotQuantity)}><i className="fas fa-plus"></i></button>
                }
            </div>
        )
    }

}

export default ChooseQuantity;

//My Shopping Cart Component
import React, { Component } from 'react';
import Swal from "sweetalert2";
import { Link } from 'react-router-dom';

import './Cart.css';
import '../../components/Css/App.css';

import Lot from './Lot';
import ChooseQuantity from './ChooseQuantity';

import Header from '../../components/Header/Header';
import Tabbar from '../../components/Tabbar/Tabbar';

const separator = '/';
class Cart extends Component {
    constructor(props) {
        super(props);
        this.state = {}
        this.choosePayment = this.choosePayment.bind(this);
    }

    async componentDidMount() {
        const company_info = JSON.parse(localStorage.getItem('company_info'));
        await this.setState({ 
            company_image: company_info.imagem,
            company_hash: company_info.numeroUnico,
        })
        const cart = JSON.parse(localStorage.getItem('cart'));
        const total = cart.total;
        if(cart){
            const {
                events,
                events: { tickets },
                total
              } = cart;
            await this.setState({
                cart,
                events,
                tickets: tickets,
                banner_app: events.banner_app,
                eventName: cart.events.name,
                priceTotal: total.price,
                quantity: total.totalQuantity,
                lots: tickets.lot,
                maxTotalItems: cart.events.max_purchase,
                selectedLots: tickets.lot,
                total: total.totalQuantity
            });
        }

        const teste = JSON.parse(localStorage.getItem('teste'))
        this.setState({teste: teste})
    }    

    choosePayment() {
        Swal.fire({
            title: 'Método de Pagamento',
            text: 'Qual o médtodo de pagamento que você deseja usar?',
            confirmButtonText: 'Cartão de Crédito',
            confirmButtonColor: '#007bff',
            showCancelButton: true,
            cancelButtonText: 'Boleto Bancário',
            cancelButtonColor: '#007bff',
        }).then((result) => {
            if (result.value) {
                this.props.history.push('/checkout');
            } else{
                this.props.history.push('/checkout-bank-slip');
            }
        })
    }

    render() {
        return (
            <div>
                <Header Title="Carrinho" ToPage="/" />
                {
                    this.state.total <= 0 ?
                    <Tabbar />
                    :
                    null
                }
                <div className="cart">
                    <div className="container-fluid">
                        {
                            this.state.total > 0 ?
                            <div>
                                <div className="box-price">
                                    <div className="row box-default ">
                                        <div className="col col-price">
                                            <h6>{this.state.quantity} INGRESSO{this.state.quantity > 1 ? 'S' : ''}</h6>
                                            <h5>R$ {parseFloat(this.state.priceTotal).toFixed(2).replace('.', ',')}</h5>
                                        </div>
                                    </div>
                                </div>

                                <div className="row">
                                    <div className="col-12 col-image no-padding">
                                        <img src={this.state.banner_app} alt="" />
                                    </div>
                                </div>

                                <div className="row">
                                    <div className="col">
                                        <h1 className="event-title text-center">{this.state.eventName}</h1>
                                    </div>
                                </div>

                                <div className="padding-15">
                                    {
                                        this.state.lots.map((lot, l) => 
                                        <div key={l}>
                                            {
                                                lot.quantity > 0 ?
                                                    <div>
                                                        <div className="row">
                                                            <div className="col">
                                                                <h5 className="ticket-name">{lot.ticketName}</h5>
                                                            </div>
                                                        </div>
                                                        <div className="row">
                                                            <div className="col-8">
                                                                <h5 className="lot-name">
                                                                    { lot.lotName } - ({lot.lotNumber}º Lote)
                                                                </h5>
                                                                <h6 className="lot-price">
                                                                    R$ {lot.lotPrice.replace('.', ',')} ({lot.lotPrice.replace('.', ',')} + {lot.lotPriceTax.replace('.', ',')})
                                                                </h6>
                                                            </div>
                                                            <div className="col-4">
                                                                <h3 className='lot-big-price'>
                                                                    {lot.lotPrice.replace('.', ',')}
                                                                </h3>
                                                            </div>
                                                        </div>
                                                        <div className="row">
                                                            <div className="col align-items">
                                                                <ChooseQuantity
                                                                    lotQuantity={lot.quantity}
                                                                    maxPurchase={this.state.events.max_purchase}
                                                                    totalTickets={this.state.total}
                                                                    lot={lot}
                                                                    events={this.state.events}
                                                                    maxTotalItems={this.state.maxTotalItems}
                                                                    onCLick={this.onClick}
                                                                />
                                                            </div>
                                                        </div>
                                                    </div>
                                                    :
                                                null

                                            }
                                        </div>
                                        )
                                    }
                                    
                                    <div className="row cart-footer" style={{ marginRight: '-15px', marginLeft: '-15px', backgroundColor: '#f4f7fa' }}>
                                        <button className="col col-purchase" style={{ justifyContent: 'center', alignItems: 'center' }} onClick={this.choosePayment}>
                                            Confirmar Comprar
                                        </button>
                                    </div>
                                </div>
                            </div>
                            :
                            <div className='padding-15'>
                                <div className="mt-5 no-margin box-default row">
                                    <div className="col">
                                        <h3 className="text-center">
                                            Não há nenhum item em seu carrinho.
                                        </h3>
                                        <p className="text-center">								
                                            Toque no botão <strong>Buscar Eventos</strong> para iniciar uma nova pesquisa.									
                                        </p>
                                        <Link className="btn btn-primary btn-block" to="/">
                                            Buscar Eventos
                                        </Link>
                                    </div>
                                </div>

                                <div className="row no-margin box-default mt-3">
                                    <div className="col">
                                        <img src={`//www.yeapps.com.br/admin/files/empresa/${this.state.company_hash}/${this.state.company_image}`} alt={`${this.state.company_name}`} />
                                    </div>
                                </div>
                            </div>
                        }
                    </div>
                </div>
            </div>
        );
    }
}

export default Cart;

//My Header Component
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
// import { withRouter } from 'react-router';
import './Header.css';
import BackButton from '../BackButton/BackButton';

class Header extends Component {
    constructor(props){
        super(props);
        this.state = {
            qtd: 0
        }
    }

    componentDidMount() {
        const qtd = JSON.parse(localStorage.getItem('qtd'));
        this.setState({qtd: qtd});
    }

    render() {
        const { Title } = this.props;
        return (
            <div>
                <nav className="navbar">
                    { this.props.Title === 'Home' ? null : <BackButton />}
                    <Link to="/cart" className="icon-cart">
                        <i className="fas fa-shopping-cart"></i>
                        <span className="badge badge-danger">
                            {this.state.qtd}
                        </span>
                    </Link>
                    <div className="navbar-brand">
                        {Title}
                    </div>
                </nav>
            </div>
        );
    }
}

export default Header;

标签: reactjs

解决方案


您需要像在 componentDidMount 中那样在 componentDidUpdate 中更新您的展示组件(Card、Header)状态。componentDidMount 仅在第一次渲染时工作一次,然后您设置在渲染中使用的状态变量。在 componentDidUpdate 中执行相同的 setState

PS,但您需要确保随着计数器的增加,您的演示组件会获得新的道具,这将触发 componentDidUpdate。在您的情况下,您使用 localStorage 但最好通过公共父容器(包含这三个组件的容器)传递数据作为卡片和标题的道具。


推荐阅读