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

Reactjs React/Redux:每当页面更改时,都会自动调用操作,reactjs,redux,react-redux,react-router,Reactjs,Redux,React Redux,React Router,我正在使用Redux制作一个简单的购物车应用程序。现在,每次我更改页面,操作都会自动被调用三次,这相当于项目数。若我转到购物车页面,removeItems操作会被调用三次,所以到目前为止我无法将项目添加到购物车。这可能是路由器的问题,但我无法发现问题所在。谁能给我解释一下有什么问题吗 Home.js import React from 'react'; import { connect } from 'react-redux'; import { addToCart } from '../act

我正在使用Redux制作一个简单的购物车应用程序。现在,每次我更改页面,操作都会自动被调用三次,这相当于项目数。若我转到购物车页面,removeItems操作会被调用三次,所以到目前为止我无法将项目添加到购物车。这可能是路由器的问题,但我无法发现问题所在。谁能给我解释一下有什么问题吗

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);
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);

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
    }
}
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;
行动

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);
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);

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
    }
}
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;
App.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);
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);

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
    }
}
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;
从“React”导入React;
从“react router dom”导入{BrowserRouter,Route,Switch};
从“./头”导入头;
从“./主页”导入主页;
从“./Cart”导入购物车;
常量应用=()=>{
返回(
)
}
导出默认应用程序;

似乎每次呈现组件时都在调用单击处理程序,而不仅仅是传递处理程序函数,因此操作会被多次触发

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

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

{this.handleClick(item.id);}}>删除

哇,真管用!非常感谢你!onClick={this.handleClick(item.id)}和onClick={()=>{this.handleClick(item.id);}之间有什么区别?我知道我是通过像第一个那样编写来调用函数的,但是第二个函数是如何工作的?很高兴它能工作!两种形式之间的区别是,在第一个形式中,您实际上在渲染期间调用了单击处理程序,而在第二个形式中,您定义了一个函数来处理单击(但不调用它)。通常我们会添加这样的单击处理程序:
onClick={myClickHandler}
,但当您传递一些参数时,实际上需要将处理程序调用包装在新的函数定义中,如
onClick={()=>{myClickHandler(myParameter);}}
是一个匿名函数定义,在单击之前不会调用它。因此,如果有参数,我写onClick={()=>{myClickHandler(myParameter);}}},如果没有,我可以删除(),只写函数名?@kayak,没错!现在我非常理解了。感谢您的解释:)