React / Redux:每当页面更改时,动作都会自动被调用

时间:2019-07-29 11:42:14

标签: reactjs redux react-redux react-router

我正在使用Redux制作一个简单的购物车应用程序。现在,每次我更改页面时,都会自动调用动作三次,其次数等于项的数量。如果我进入购物车页面,removeItems操作将被调用3次,所以到目前为止我还无法将商品添加到购物车中。这可能是关于路由器的问题,但我无法发现问题。谁能解释我的问题是什么?

Home.js

import React from 'react';
import { connect } from 'react-redux';
import { addToCart } from '../actions';

class Home extends React.Component {
    handleClick = id => {
        this.props.addToCart(id)
    }

    renderList = () => {
        return this.props.cart.slice(0, 3).map(item => {
                return (
                    <div className="card" key={item.id} style={{width: "200px", float: "left", marginRight: "20px"}}>
                        <div className="card-image">
                            <img src={item.imageUrl} alt={item.name} />
                            <span className="card-title">{item.name}</span>
                            <span to="/" 
                                className="btn-floating halfway-fab waves-effect waves-light red"
                                onClick={this.handleClick(item.id)}
                            >
                                <i className="material-icons">add</i>
                            </span>
                        </div>

                        <div className="card-content">
                            <p>{item.desc}</p>
                            <p><b>${item.price}</b></p>
                        </div>
                    </div>
                )
            })
        }

        render() {
            console.log(this.props.cart)

        return (
            <div className="container">
                <h3>Home</h3>
                <div className="box">
                    {this.renderList()}
                </div>
            </div>
        )
    }
}

const mapStateToProps = state => {
    return { cart: state.cart.items }
}

const mapStateToDispatch = dispatch => {
    return {
        addToCart: (id) => { dispatch(addToCart(id)) }
    }
}

export default connect(mapStateToProps, mapStateToDispatch)(Home);

Cart.js

import React from 'react';
import { connect } from 'react-redux';
import { removeItem } from '../actions';

class Cart extends React.Component {
    handleClick = (id) => {
        this.props.removeItem(id);
    }

    renderList = () => {
        if (this.props.addedItems.length !== 0) {
            return this.props.addedItems.map(item => {
                return (
                    <li className="collection-item avatar" key={item.id}>
                        <div className="item-img">
                            <img src={item.imageUrl} alt={item.name} style={{width: "120px"}} />
                        </div>

                        <div className="item-desc">
                            <span className="title">{item.name}</span>
                            <p>{item.content}</p>
                            <p><b>${item.price}</b></p> 
                        </div>
                        <button 
                            className="waves-effect waves-light btn pink remove"
                            onClick={this.handleClick(item.id)}    
                        >Remove</button>
                    </li>
                )
            })            
        }
        else {
            return <p>Nothing is in cart.</p>
        }
    }

    render() {
        return (
            <div className="container">
                <div className="cart">
                    <ul className="collection">
                    {this.renderList()}
                    </ul>
                </div>
            </div>
        )
    }
}

const mapStateToProps = state => {
    return { addedItems: state.cart.addedItems }
}

const mapDispatchToProps = dispatch => {
    return {
        removeItem: (id) => {dispatch(removeItem(id))}
    }
}

export default connect(mapStateToProps, mapDispatchToProps)(Cart);

Header.js

import React from 'react';
import { Link } from 'react-router-dom';

const Header = () => {
    return (
        <nav className="nav-wrapper">
            <div className="container">
            <Link to="/" className="brand-logo">Shopping</Link>

            <ul className="right">
                <li><Link to="/">Shop</Link></li>
                <li><Link to="/cart">Cart</Link></li>
                <li><Link to="/cart"><i className="material-icons">shopping_cart</i></Link></li>
            </ul>
            </div>
        </nav>
    )
}

export default Header;

减速器

import data from '../data.json';
import { ADD_TO_CART, REMOVE_FROM_CART } from "../actions/types";

const INITIAL_DATA = {
    items: data,
    addedItems: [],
    total: 0
}

const cartReducer = (state = INITIAL_DATA, action) => {
    switch(action.type) {
        case ADD_TO_CART:
            let addedItem = state.items.find(item => item.id === action.id);
            let existedItem = state.addedItems.find(item => action.id ===item.id);

            if (existedItem) {
                addedItem.quantity += 1;
                return {
                    ...state,
                    total: state.total + addedItem.price
                }                
            }
            else {
                addedItem.quantity = 1;
                let newTotal = state.total + addedItem.price;
                return {
                    ...state,
                    addedItems: [...state.addedItems, addedItem],
                    total: newTotal
                }
            }

        case REMOVE_FROM_CART:
            let itemToRemove = state.addedItems.find(item => action.id === item.id);
            let newItems = state.addedItems.filter(item => action.id !== item.id);

            let newTotal = state.total - itemToRemove.price;

            return {
                ...state,
                addedItems: newItems,
                total: newTotal
            }

        default: 
            return state;
    }
}

export default cartReducer;

操作

import { ADD_TO_CART, REMOVE_FROM_CART } from "./types";

export const addToCart = (id) => {
    return {
        type: ADD_TO_CART,
        id
    }
}

export const removeItem = (id) => {
    return {
        type: REMOVE_FROM_CART,
        id
    }
}

App.js

import React from 'react';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import Header from './Header';
import Home from './Home';
import Cart from './Cart';

const App = () => {
    return (
        <BrowserRouter>
        <div className="app">
            <Header />

            <Switch>
                <Route exact path="/" component={Home} />
                <Route path="/cart" component={Cart} />
            </Switch>
            </div>
        </BrowserRouter>        
    )
}

export default App;

1 个答案:

答案 0 :(得分:1)

似乎您实际上在渲染组件时实际上都在调用单击处理程序,而不仅仅是传递处理程序功能,因此这就是多次触发操作的原因。

例如,在您的Home.js组件中,将以下代码从以下位置更改:

<span to="/" className="btn-floating halfway-fab waves-effect waves-light red" onClick={this.handleClick(item.id)} >

收件人:

<span to="/" className="btn-floating halfway-fab waves-effect waves-light red" onClick={() => { this.handleClick(item.id); }} >

Cart.js上的相同内容,改为:

<button className="waves-effect waves-light btn pink remove" onClick={this.handleClick(item.id)}>Remove</button>

至:

<button className="waves-effect waves-light btn pink remove" onClick={() => {this.handleClick(item.id); }}>Remove</button>