每当用户单击按钮时,我都试图调用handleClick方法,但是页面上的任何内容都不会呈现,并且出现错误“未捕获的ReferenceError:handleClick未定义”。
组件的实现:
import {createElement} from 'react';
import {add} from '../action/cart';
import {connect} from 'react-redux';
import styles from './styles.css';
handleClick = (id) => {
add(id);
this.setState((prevState) => ({
...prevState,
items: prevState.items.map(
(item) =>
id === item.id
? {id, quantity: item.quantity + 1}
: {...item}
),
}));
};
const Product = ({add, id, title, image}) => (
<div className={styles.product} onClick={handleClick(id)}>
<img src={image} alt={title} className={styles.productImage}/>
{title}
</div>
);
export default connect(() => ({}), {add})(Product);
这与购物车组件共享状态:
const Cart = connect(
() => ({}),
{clear}
)(({items, clear, total}) => {
return (
<div>
<Heading><FontAwesomeIcon icon={faShoppingCart} /> Cart</Heading>
{items.length ? <button onClick={clear}>Clear all items</button> : null}
<table>
<thead>
<tr>
<th>Product</th>
<th>Price</th>
<th>Quantity</th>
<th>Total</th>
</tr>
</thead>
<tbody>
{items.map(({...item}, id) => (
<Item {...item} key={id} />
))}
</tbody>
</table>
{items.length ?
<div className={styles.total}>${total}</div>
: <div>Your cart is empty!</div>}
</div>);
});
export default connect((state) => {
return {
items: state.cart.items,
total: reduce(
(sum, {id, quantity}) => sum + products[id].price * quantity,
0,
state.cart.items
).toFixed(2).replace(/\d(?=(\d{3})+\.)/g, '$&,'),
};
})(Cart);
它引用了此操作:
import {ADD_ITEM, SET_QUANTITY, CLEAR_ITEMS} from './types';
import {createAction} from 'redux-actions';
export const add = createAction(ADD_ITEM);
export const setQuantity = createAction(SET_QUANTITY);
export const clear = createAction(CLEAR_ITEMS);
使用此减速器
[ADD_ITEM]: (state, {payload: id}) => ({
...state,
items: [
...state.items,
{id, quantity: 1},
],
}),
答案 0 :(得分:1)
您正在为Product
创建一个无状态组件,this
不应在无状态组件内部使用(更不用说setState
的处理程序了)。相反,您应该使Product
成为常规组件,如下所示:
编辑(删除了先前的代码)
好的,我看到您已经更新了帖子中的代码。因此,以下几件事可能会让您绊倒:
如果还没有这样做,请摆脱setState
中的handleClick
。该逻辑应该在redux动作之内,因为您的所有状态似乎都在redux状态树中。
您为Cart
呼叫了两次connect。删除第一个电话,其中:
const Cart = connect(
() => ({}),
{clear}
)(({items, clear, total}) => {
应成为:
const Cart = ({items, clear, total}) => {
我想你是这个意思...
<tbody>
{items.map(({...item}, id) => (
<Item {...item} key={id} />
))}
</tbody>
...就是这样(我假设products
存在于您的代码库中,因为您在connect
的{{1}}调用中使用了它):
Cart
我想你是这个意思:
<tbody>
{items.map(({...item}, id) => (
<Product {...products[id]} {...item} key={id} />
))}
</tbody>
要这样:
{
total: reduce(
(sum, {id, quantity}) => sum + products[id].price * quantity,
0,
state.cart.items
).toFixed(2).replace(/\d(?=(\d{3})+\.)/g, '$&,'),
}
然后,您需要从已删除的{
total: state.cart.items.reduce(
(sum, {id, quantity}) => sum + products[id].price * quantity,
0,
).toFixed(2).replace(/\d(?=(\d{3})+\.)/g, '$&,'),
}
调用中添加clear
道具,回到剩下的道具中,剩下的就是:
connect
要回到先前删除的export default connect(
state => ({
items: state.cart.items,
total: state.cart.items.reduce(
(sum, {id, quantity}) => sum + products[id].price * quantity,
0,
).toFixed(2).replace(/\d(?=(\d{3})+\.)/g, '$&,'),
}),
{clear},
)(Cart);
,setState
的减速器可能类似于以下内容:
ADD_ITEM
我认为以上所有内容都应该使您接近所有工作。
编辑2
要回答您的评论,是因为您没有在减速器中处理CLEAR_ITEMS操作吗?也许您需要减速器看起来像这样?
[ADD_ITEM]: (state, {payload: id}) => {
const itemAlreadyInCart = state.items.find(i => i.id === id);
if (itemAlreadyInCart) {
return {
...state,
items: state.items.map(
(item) =>
id === item.id
? {id, quantity: item.quantity + 1}
: {...item}
),
}
}
else {
return {
...state,
items: [
...state.items,
{id, quantity: 1, },
],
}
}
},
顺便说一句,我也注意到了另一个问题。我之前发布了此更改:
[ADD_ITEM]: (state, {payload: id}) => {
const itemAlreadyInCart = state.items.find(i => i.id === id);
if (itemAlreadyInCart) {
return {
...state,
items: state.items.map(
(item) =>
id === item.id
? {id, quantity: item.quantity + 1}
: {...item}
),
}
}
else {
return {
...state,
items: [
...state.items,
{id, quantity: 1, },
],
}
}
},
[CLEAR_ITEMS]: (state) => {
return {
...state,
items: [],
}
},
但是<tbody>
{items.map(({...item}, id) => (
<Product {...products[id]} {...item} key={id} />
))}
</tbody>
中的id
不是项的id键,而是map(({...item}, id)
函数提供的数组的索引。您可能想要执行以下操作:
map
答案 1 :(得分:0)
似乎方法未绑定到事件。您可以使用进行显式尝试 .bind方法
答案 2 :(得分:0)
从示例中很难看出,但是如果要将方法从父组件传递到子组件,则需要对其进行绑定。这可以通过多种方式完成,但是直接开始的地方应该是onClick = {handleClick(id).bind(this)}
但是,在此示例中,尚不清楚您如何“共享状态”。如果您可以阐明应用程序的结构,那么我将阐明如何适当地绑定该方法。
答案 3 :(得分:0)
由于handleClick确实设置了setState,因此我建议您将事件处理函数移至类组件(也称为statefull组件),并将该函数作为prop传递给Product组件。由于产品组件是功能组件或无状态组件,因此不建议您更改状态。如果要在Product组件本身中处理handleClick,则将Product组件更改为statefull组件
handleClick也是一个箭头功能,因此您无需手动绑定。