Javascript 如何在redux中分派函数?

Javascript 如何在redux中分派函数?,javascript,reactjs,react-native,redux,react-redux,Javascript,Reactjs,React Native,Redux,React Redux,我在redux商店中有一个购物车数组,其中包含我添加到购物车中的所有项目 像这样 const initialState = { cart: [ { product: { id: 1, name: 'Pizza cheese', price: 100, image: require('../../assets/food-3.png'), description: 'Tempor aute cul

我在redux商店中有一个购物车数组,其中包含我添加到购物车中的所有项目

像这样

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,
    },
  ],
};
我有一个输入来添加优惠券代码,当我添加它时,应该会降低总价格, 那么,如果我没有在商店中存储总计,我如何实现这些目标呢? 并在添加此优惠券后呈现总价

这是我的代码片段

reducer/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;


}

};
导入{
加上优惠券,
将\添加到\购物车,
从车上减去,
再加上车上的,
删除项目,
}来自“../actions/types”;
导出默认cartReducer=(状态、操作)=>{
控制台日志(操作);
开关(动作类型){
案例添加到购物车:{
返回{
购物车:[
…state.cart,
{
产品:action.productInfo,
数量:action.quantity,
},
],
};
}
case PLUS_从_车中取出:{
返回{
……国家,
购物车:state.cart.map(项目=>{
if(item.product.id==action.productInfo.product.id){
返回{
…项目,
数量:action.quantity+1,
};
}
退货项目;
}),
};
}
案例减去_购物车中的_:{
返回Object.assign({},state{
购物车:state.cart.map(项目=>{
if(item.product.id==action.productInfo.product.id){
返回Object.assign({},item{
数量:
action.quantity product.id!==action.productInfo.product.id,
),
],
});
}
案例添加优惠券:{//这是
console.log(state.cart);
返回{
……国家,
新总数:
state.cart.reduce(
(总计,项目)=>总计+项目数量*项目产品价格,
0,
) - 50,
};
}
违约:
返回状态;
}
};
购物车屏幕

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);
import React,{Component}来自'React';
进口{
有生气的
尺寸,
平面列表,
滚动视图,
样式表,
文本,
文本输入,
可触摸不透明度,
看法
}从“反应本机”;
从“反应本机手势处理程序/Swipeable”导入Swipeable;
从“反应本机矢量图标/羽毛”导入图标;
从'react redux'导入{connect};
从“../components/CartIcon”导入CartIcon;
从“../components/CartItem”导入CartItem;
进口{
从购物车,
plusFromCart,
删除项目,
}来自“../store/actions/actions”;
类CartsScreen扩展组件{
状态={
交货日期:15,
总计:this.props.total,
优惠券:“”,
};
Applay优惠券=()=>{//这是
const{coupon}=this.state;
如果(优惠券=‘免费’){
this.props.add优惠券();
}
};
handleIncreaseQuantity=(产品、数量)=>{
此.props.increaseQuantity(产品、数量);
};
处理数量=(产品、数量)=>{
本.道具.减量(产品,数量);
};
handleremovietem=产品=>{
此.props.removeProduct(产品);
};
render(){
返回(
this.setState({优惠券})}
占位符=“写入优惠券代码”
/>
this.applay优惠券()}>
申请
小计
{this.props.total.toFixed(2)}$
送货费
{this.state.delivery}$
全部的
{this.props.total+this.state.delivery}
之后:{this.props.newTotal}$
结账
);
}
}
常量mapStateToProps=状态=>{
返回{
cartItem:state.cart,
总计:state.cart.reduce(
(总计,项目)=>总计+项目数量*项目产品价格,
0,
),
新总数:state.newTotal
};
};
const mapDispatchToProps=调度=>{
返回{
增加数量:(产品、数量)=>
派送(加上购物车(产品、数量)),
减量数量:(产品、数量)=>
发货(运输车(产品、数量)),
removeProduct:product=>dispatch(removeItem(product)),
添加优惠券:()=>{
分派({类型:'添加优惠券'});
},
};
};
导出默认连接(
MapStateTops,
mapDispatchToProps,
)(Cartscreen);

我的建议是不要在状态中存储冗余(派生)信息。这意味着您不需要(也不应该!)将总数存储在状态中。这是一个问题的主要原因是它给了您的状态一个自相矛盾的机会…如果您的状态的
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;
}
然后,在代码中任何需要获得总数的地方,都可以简单地使用此函数。在
MapStateTrops
中包含此类函数并不少见:

const mapStateToProps = state => ({
  total: calculateTotal(state);
});

如果您最终获得了大量派生状态,您可能会看到使用选择器库的一些优势,例如它可以帮助您构建从其他选择器派生的选择器,并实现记忆以提高性能。

创建一个操作来计算您的购物车总计,然后将优惠券添加到总计中如何?无论如何,您需要将总计存储在st中oreI绝对不建议在状态中单独维护总计。相同信息的两个来源通常不起作用。谢谢,Nick,很抱歉,但是calculateTotal函数应该在哪个文件?Reducer或任何屏幕上,我想进行计算,是的,我会检查Reselect,该函数可以在任何地方。我希望可能只是从它自己的文件(例如calculateTotal.js)中导出它嘿@Nick,你说的
是什么意思在mapStateToProps中包含这类函数并不少见
@DevAS理论上,你可以从组件本身内部调用函数,但是在mapStateToProps函数中这样做是很常见的。是的,正确的术语是,当你点击按钮时,你发出一个动作离子