javascript - 如何在 redux 中调度函数?
问题描述
我在 redux 商店中有一个 Cart 数组,其中包含我添加到购物车的所有项目
像这样
const initialState = {
cart: [
{
product: {
id: 1,
name: 'Pizza cheese',
price: 100,
image: require('../../assets/food-3.png'),
description: 'Tempor aute culpa ad voluptate aliquip ad ad laboris.',
},
quantity: 3,
},
{
product: {
id: 2,
name: 'Steak meal',
price: 200,
image: require('../../assets/food-2.png'),
description: 'Tempor aute culpa ad voluptate aliquip ad ad laboris.',
},
quantity: 2,
},
],
};
并且我有一个添加优惠券代码的输入,当我添加它时应该会降低总价,那么如果我没有在商店中存储总价,我该如何实现这些?并在添加此优惠券后呈现总价!
这是我的代码片段
减速器/index.js
import {
ADD_COUPON,
ADD_TO_CART,
MINUS_FROM_CART,
PLUS_FROM_CART,
REMOVE_ITEM,
} from '../actions/types';
export default cartReducer = (state, action) => {
console.log(action);
switch (action.type) {
case ADD_TO_CART: {
return {
cart: [
...state.cart,
{
product: action.productInfo,
quantity: action.quantity,
},
],
};
}
case PLUS_FROM_CART: {
return {
...state,
cart: state.cart.map(item => {
if (item.product.id === action.productInfo.product.id) {
return {
...item,
quantity: action.quantity + 1,
};
}
return item;
}),
};
}
case MINUS_FROM_CART: {
return Object.assign({}, state, {
cart: state.cart.map(item => {
if (item.product.id === action.productInfo.product.id) {
return Object.assign({}, item, {
quantity:
action.quantity <= 1 ? action.quantity : action.quantity - 1,
});
}
return item;
}),
});
}
case REMOVE_ITEM: {
return Object.assign({}, state, {
cart: [
...state.cart.filter(
({product}) => product.id !== action.productInfo.product.id,
),
],
});
}
case ADD_COUPON: { // here is
console.log(state.cart);
return {
...state,
newTotal:
state.cart.reduce(
(total, item) => total + item.quantity * item.product.price,
0,
) - 50,
};
}
default:
return state;
}
};
购物车屏幕
import React, {Component} from 'react';
import {
Animated,
Dimensions,
FlatList,
ScrollView,
StyleSheet,
Text,
TextInput,
TouchableOpacity,
View,
} from 'react-native';
import Swipeable from 'react-native-gesture-handler/Swipeable';
import Icon from 'react-native-vector-icons/Feather';
import {connect} from 'react-redux';
import CartIcon from '../components/CartIcon';
import CartItem from '../components/CartItem';
import {
MinusFromCart,
plusFromCart,
removeItem,
} from '../store/actions/actions';
class CartsScreen extends Component {
state = {
delivery: 15,
total: this.props.total,
coupon: '',
};
applayCoupon = () => { // here is
const {coupon} = this.state;
if (coupon == 'Free') {
this.props.addCoupon();
}
};
handleIncreaseQuantity = (product, quantity) => {
this.props.increaseQuantity(product, quantity);
};
handleDecreaseQuantity = (product, quantity) => {
this.props.decreaseQuantity(product, quantity);
};
handleRemoveItem = product => {
this.props.removeProduct(product);
};
render() {
return (
<View style={styles.container}>
<View style={{marginBottom: 5}}>
<View
style={{
borderColor: '#d7d7d7',
margin: 15,
borderWidth: 1,
padding: 15,
borderRadius: 10,
flexDirection: 'row',
justifyContent: 'space-between',
}}>
<TextInput
value={this.state.coupon}
style={{width: '80%'}}
onChangeText={coupon => this.setState({coupon})}
placeholder="Write coupon code"
/>
<TouchableOpacity onPress={() => this.applayCoupon()}>
<Text style={{color: '#f00'}}>Apply</Text>
</TouchableOpacity>
</View>
<View
style={{
paddingVertical: 5,
marginBottom: 5,
flexDirection: 'row',
justifyContent: 'space-between',
paddingHorizontal: 15,
}}>
<Text style={{fontSize: 15}}>Subtotal</Text>
<Text style={{fontSize: 15}}>{this.props.total.toFixed(2)}$</Text>
</View>
<View
style={{
paddingVertical: 5,
marginBottom: 5,
flexDirection: 'row',
justifyContent: 'space-between',
paddingHorizontal: 15,
}}>
<Text style={{fontSize: 15}}>Delivery Fee</Text>
<Text style={{fontSize: 15}}>{this.state.delivery}$</Text>
</View>
<View
style={{
borderTopColor: '#ddd',
borderTopWidth: 1,
paddingVertical: 10,
alignSelf: 'center',
}}>
<View
style={{
paddingVertical: 5,
marginBottom: 5,
flexDirection: 'row',
justifyContent: 'space-between',
paddingHorizontal: 15,
}}>
<Text style={{fontWeight: '700', fontSize: 18}}>Total</Text>
<Text style={{fontWeight: '700', fontSize: 18}}>
{this.props.total + this.state.delivery}
</Text>
</View>
<Text
style={{fontWeight: '700', paddingHorizontal: 15, fontSize: 18}}>
after: {this.props.newTotal} $
</Text>
<TouchableOpacity
style={{
justifyContent: 'center',
alignItems: 'center',
padding: 15,
borderRadius: 10,
width: width - 20,
backgroundColor: '#f10',
}}>
<Text style={{fontSize: 15, color: '#fff'}}>Checkout</Text>
</TouchableOpacity>
</View>
</View>
</View>
);
}
}
const mapStateToProps = state => {
return {
cartItem: state.cart,
total: state.cart.reduce(
(total, item) => total + item.quantity * item.product.price,
0,
),
newTotal: state.newTotal
};
};
const mapDispatchToProps = dispatch => {
return {
increaseQuantity: (product, quantity) =>
dispatch(plusFromCart(product, quantity)),
decreaseQuantity: (product, quantity) =>
dispatch(MinusFromCart(product, quantity)),
removeProduct: product => dispatch(removeItem(product)),
addCoupon: () => {
dispatch({type: 'ADD_COUPON'});
},
};
};
export default connect(
mapStateToProps,
mapDispatchToProps,
)(CartsScreen);
解决方案
我的建议是不要在状态中存储冗余(派生)信息。这意味着您不需要(也不应该!)将总数存储在状态中。这是一个问题的主要原因是它给了你的状态一个自相矛盾的机会......如果你的状态的total
关键不等于项目总数的总和,你就有一个大问题!
相反,您可以创建一个计算总数的函数,并在需要时简单地调用它。例如:
const calculateTotal = state => {
let total = state.cart.reduce((total, item) => {
return total + item.quantity * item.product.price
}, 0);
// Assuming you just have one coupon, you could maintain a boolean in state
if (state.hasCoupon) {
total -= 50;
}
return total;
}
然后,在您需要获取总数的代码中的任何位置,您都可以简单地使用此函数。将这种功能包含在以下内容中并不少见mapStateToProps
:
const mapStateToProps = state => ({
total: calculateTotal(state);
});
如果您最终得到很多派生状态,您可能会看到使用像Reselect这样的选择器库的一些优势,它可以帮助您构建从其他选择器派生的选择器并实现记忆以提高性能。
推荐阅读
- python - 如何从 python/Django 中的短数字或完整形式数字中获取上一个月份的名称
- node.js - 如何在 mongodb 中运行 2 个销毁查询?
- html - 如何移动hr元素位置?
- visual-studio - 是否可以在 Visual Studio 中编译在 CCS ver8.0 中创建的程序
- notepad++ - 是否可以在 Notepad++ 中找到任意字符?
- login - 更改 asp.net 中的默认登录页面 UI
- angular - 如何测试组件是否在 Angular 7 业力测试中动态加载?
- python - 在一个 python 环境中维护不同版本的包
- c# - 文本框的日期时间选择器未在 asp.net 中显示
- azure - azure cosmosdb - 禁用默认二级索引