Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

I have a Cart array in the redux store that contains all the items I added it to cart

like this

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,
    },
  ],
};

and I have an input to add a coupon code, and when I added it should decrease the total price, so how can I achieve these if I didn't store a total in the store? and render the total price after adding this coupon!

here is my code snippet

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;


}

};

cart screen

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);
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
383 views
Welcome To Ask or Share your Answers For Others

1 Answer

My recommendation would be to not store redundant (derived) information in state. This means you don't need to (nor should you!) store the total in the state. The main reason this is a problem is that it gives your state an opportunity to contradict itself... if your state's total key doesn't equal the sum of the item totals, you've got a big problem!

Instead, you can create a function that calculates the total and simply call that when you need it. For example:

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

And then, anywhere in your code you need to get the total, you can simple use this function. It's not uncommon to include this sort of function in mapStateToProps:

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

If you end up with a lot of derived state, you may see some advantages from using a selector library like Reselect which can help you build selectors derived from other selectors and implements memoization for performance boosts.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...