- Read Tutorial
- Watch Guide Video
The way we do this is by developing a couple of actions. Let's start with the Add to Cart, when we hit this we want to add a new cart product to our cart products array. So let's go ahead and head into vs code, and close this terminal here and let's go into shop.js
in our actions folder... well let's go into user.js
in our actions folder.
So basically this is going to be adding to the user's cart array, okay so what we want to do is say export function addCartProduct and what we're going to do is say return and we'll say type ADD_CART_PRODUCT and we'll say payload is basically just one of these items here. Now the thing is we're going to have to check the id and see if the product exists already but we'll do that in the reducer.
Okay so we're adding the product, and what we want to do is not add in this product, we want to take it in. So we'll say product and what we'll do is we will cut this out and we will say that product is product, okay we're taking it in. Now the id is also going to be generated so let's not worry about that. Now what we'll do is we will basically just throw in the product right, we just want to throw in the product so let's say payload is product.
user.js
export function addCartProduct(product) { return ({ type: ADD_CART_PRODUCTS, payload: product }) }
All right, now what we want to do is make this type so let's copy it, and let's go up here to our imports and put a comma then paste it.
import { SET_USER_PURCHASES, SET_PURCHASE_DETAIL, SET_CART_PRODUCTS, ADD_CART_PRODUCTS } from './types';
Now, lets go into types.js
and let's go into user cart and let's say export constant add cart product is equal to add cart product.
types.js
// USER CART export const SET_CART_PRODUCTS = 'SET_CART_PRODUCTS'; export const ADD_CART_PRODUCTS = 'ADD_CART_PRODUCTS';
All right now what we're going to do is head over to the userReducer.js
, in the userReducer we're going to import this type.
userReducer.js
import { SET_USER_PURCHASES, SET_PURCHASE_DETAIL, SET_CART_PRODUCTS, ADD_CART_PRODUCT } from '../actions/types';
So make sure you import this type from actions/types. Now the idea here is we're going to go through our cart products and see if this product exists, if it doesn't we'll add the product on, if it does we'll increment the quantity in our cart product. Okay, so let's go to here in let's say case ADD_CART_PRODUCT
and at the bottom let's just say return ...state and we'll say cartProducts is an array.
userReducer.js
export default function(state = INITIAL_STATE, action) { switch (action.type) { case ADD_CART_PRODUCT: return { ...state, cartProducts: [] }
So first let's get the cart products let's say const cart products is equal to state.cartProducts.map and we'll say cartProduct and then we'll put an arrow function, and here's what we're going to do. We're going to say newCP for cart product, is equal to action.payload. Basically we want to say okay if cart product.product._id is equal to newCP._id.
So if we have a cart product with a product with an ID. Right. So if we have a cart product that contains a product like JavaScript in the browser sticker. If that has an ID equal to newCP._id then we have that item in our cart already, we just need to increment the quantity right. So lets make a variable up here saying var exists is equal to false, by default it's false.
Okay, if it reaches that and it finds one we'll say yeah exists is equal to true it exists already in our cart. Now if it never does that its going to be false still right, so we want to add it on. So we'll see if exists is equal to false then what we want to do is first let's make this a variable cart product and then we'll say cartProducts.push and we'll throw a new object on okay.
Now in order to get the id for this new cart product all we need to say is state.cartProducts.length and we'll say plus one, that way we can get a new ID. We could also use something like math.random. Now this is all going to be handled on the back end anyway, so most of this you don't really need to remember except for it is good to understand it just because it will further your programming ability regardless.
So now what we need to do is throw cart product on here. Okay so we just need to say product because that is what this is, okay so product and newCP.
userReducer.js
export default function(state = INITIAL_STATE, action) { switch (action.type) { case ADD_CART_PRODUCT: var exists = false const newCP = action.payload; var cartProducts = state.cartProducts.map(cartProduct => { if(cartProduct.product._id == newCP._id) { exists = true } }) if(exists == false) { cartProducts.push({ _id: state.cartProducts.length + 1, product: newCP }) }
All right, so that should handle the logic side of things, this is typically what you would do on the backend side of things. But by doing this I can give you a higher understanding of how this works by not just building the backend then having you hit endpoints. Normally what we'd do is we would just hit an endpoint and pass in the newCP and the it'd handle it all for us because we've written that code on the backend.
So what we want to do now is we want to put this cart product back into our state so cartProducts. Now this should be good but obviously we might run into an error like we've done many times alright, that's just how programming is. So let's go ahead and go into our shopProduct.js
and initiate this call. And basically we need to import star as actions we have access to it, and then we need to import connect from react-redux and then we need to connect this component to our store to our actions.
shopProduct.js
import React, { Component } from 'react'; import Quantity from '../quantity'; import GreenPriceTag from '../greenPriceTag'; import * as actions from '../../actions'; import { connect } from 'react-redux';
So let's go down here, and let's say ShopProduct is equal to connect and then we'll say null and then we'll pass in the actions and then ShopProduct because we don't want access to our mapStateToProps we don't need it, we're just trying to modify state we're not trying to pull it into this component.
ShopProduct = connect(null, actions)(ShopProduct);
Okay, onClick it says this.handleAddToCart okay. Let's say when we remove cart hidden so when we open it up we will initiate this call, so let's say this.props.addProductToCart right, something like that, and we need to pass in the product. So the product, let's just verify that this is correct and then we need to put it in index. So let's just go into our user.js
it's called AddCartProduct
. Okay, so we'll go into index.js
in our actions and we'll take it out of user, and then we will export it out as well.
index.js
import { fetchUserPurchases, setPurchaseDetail, fetchCartProducts, addCartProduct } from './user';
export {
setHeaderLinks,
setNavbarlinks,
changeNavbarActive,
fetchUserPurchases,
setPurchaseDetail,
fetchCartProducts,
addCartProduct,
fetchShopCategories,
fetchShopProducts,
filterProductsWithCategoryId,
filterProductsWithQuery
}
Now what we're going to do is we are going to go out of here, we're going to go back into shopProduct.js
and we're going to say this.props.addCartProduct
. Okay, now what we need to do is pass in product okay. Now let's verify that we're taking in a product object from there so let's go into user.js
in our actions, okay we're taking it in and putting it as the payload. Okay, now what we need to do is pass it, now we have access to it already in props see how we're getting the id, title, description, and price. That's because back in shop.js
in components we are just throwing the product directly in there so we have all of the product okay.
The problem is we're passing in a key as well, so we don't want the key in that object okay. So what we want to do is go into our component here and when we're adding it to the product we want to do this, we want to say let's pass in an object and we'll say id, title, description, price, and let's see what else we need to add on there, what else was there belongsTo? Okay, belongsTo.
Now, let's go check, so we have five in here right now. Let's go check what belongs in that model. So we go to user.js
in actions. So belongsTo, price, description, I'm just going to copy this so I can reference it, or I'll just throw it to the side here. Okay, we have the ID, title, description, price, and belongsTo. So that's excellent, that's what we need to pass into, the only problem is we don't have access to this directly in here.
So what we need to do is pull it out of props. So let's say constant and then let's copy this object and then say is equal to this.props, that way we don't have random keys in our products in the backend, right. Okay, so let's go ahead and let's test this out and see if it works. Let's go to our application in the browser and let's open this up. Now let's not do anything yet, let's look and see how many cart products we have, we have 2 right.
So when we hit JavaScript in the browser it should remain as two and increment this to quantity 3 okay. Now I don't remember saying quantity plus equals 1. So let's go back to vs code and before we try it out let's go into our user reducer and then it says if exists equals false, what we'll do when we say exists is true. We will just say cartProduct.
and we'll say quantity += 1
. Okay now there's a chance this doesn't work but we'll see.
Okay, so we just wrote a lot of code, let's go see if it actually works. So it should just increment this to three. All right, we got an error.
Okay, so let's see what this error is, let's debug it. It says cannot read property id undefined in shop.js line 12. Okay, so let's go to shop.js, line 12. Okay, so this is likely hitting our reducer, so let's go to shop.js in our actions that's what I meant in our actions, line 12. Hmm interesting, this is not making sense. So shopCart.js
line 12, my bad. Okay, line 12 cannot read property id of undefined which means we probably messed something up, which means it probably deleted our entire array.
So let's go to Chrome, let's go to our redux dev tools and you'll see cart products is now null, so we're doing something wrong in our reducer. Let's go to vs code, and let's go into our userReducer.js
okay. In our userReducer we're doing something wrong here and it's that we are not... and we had this problem before, so what we're going to do is we are going to not copy it this way, we're going to do this. We're going to say right here. Var cartProducts is equal to an array, okay var cartProducts is equal to an empty array.
When we go over each one of these at the very end we are going to push to that array. All right push(cartProduct) that should fix our problem.
userReducer.js
export default function(state = INITIAL_STATE, action) { switch (action.type) { case ADD_CART_PRODUCT: var exists = false const newCP = action.payload; var cartProducts = [] state.cartProducts.map(cartProduct => { if(cartProduct.product._id == newCP._id) { exists = true cartProduct.quantity += 1; } cartProducts.push(cartProduct); })
Okay let's go into our application and see if it works. Let's hit this, let's add, and we'll see now that we have a new set of data okay, this has 3 now and not 2. Let me show you that one more time, see we have 4 now. When we hit graph database it should increment to 2 and this should stay at 4.
Okay, looks great to me. Let's go ahead and just open this and see if it doesn't do anything, all right looks good to me. Now we need to test one more case and that's adding an item that doesn't exist in our cart. So let's scroll down to full stack development and let's hit add, and you'll see now that it adds but our quantity doesn't have a value.
So let's go and fix this problem. Let's go to vs code and we need to say in cartProducts.push
in userReducer.js
on line 37-ish right around here we never attached the quantity. Let's put a comma and say quantity 1, because obviously this is our first item we don't need to increment anything. It's the first time we're pushing this to an array, we just need to put one.
userReducer.js
export default function(state = INITIAL_STATE, action) { switch (action.type) { case ADD_CART_PRODUCT: var exists = false const newCP = action.payload; var cartProducts = [] state.cartProducts.map(cartProduct => { if(cartProduct.product._id == newCP._id) { exists = true cartProduct.quantity += 1; } cartProducts.push(cartProduct); }) if(exists == false) { cartProducts.push({ _id: state.cartProducts.length + 1, product: newCP, quantity: 1 }) }
Okay let's give it a shot. Let's go to Chrome and let's reload our page, let's close the terminal and let's try this one more time. All, add to cart, increments to three full stack development looks like it closed it. Okay, the reason it closed is because they add when we were over here okay and that's expected, but we're going to put an overlay so we can't even do that later on anyway, don't worry about it.
Let's try it again because that bug won't even be maintained, like we won't even be able to access that button when the carts open, that's the idea. Okay, Javascript in the Browser gives us 3, graph database gives us 2, graph database again gives us 3, full stack development gives us an additional full stack development with 1, lets hit the user interface design gives us user interface design. Let's close it and click advanced oop, alright we've got advanced object oriented programming. Let's hit that one more time, we've got 2 of those now.
So really awesome, works great and you might be wondering how does this work though in the backend, how does this work? And it's literally the same thing. Okay, we just wrote all the backend logic in the frontend okay. Normally you'd write this stuff on the backend, you'd just pass like a product with it and then you'd do all of this on the backend. So we're just doing all of the backend on the frontend okay but we don't actually have backend okay.
All right we're not going to be actually hooking up a backend in this app, but I'm building a course showing you how to do this in Python. So if you're interested in learning how to basically build the backend for this app that's the course you need to watch after finishing this one.
Okay let's go to Chrome, you'll see that this is all working, and this is finally working. It took forever but it works great and it will give you a really good head start when we actually get to the Python course if you do it. All right, so that works great.
Let's go ahead and let's just move onto the checkout now. In the next video we want to move on to this component here okay.
So let's just have a small overview of what we have to do before we move on. We've got to build this, we already have all the cart products so it can be really simple, it's literally just the frontend just have to kind of map the data over. Okay proceed to check out, we've got a login, we've already built that. So we have the order review right, then we have the shipping address really simple just another form.
Then we have a modal and then we have payment information with another model. So really all we have left is a modal, let's hit add to cart. All we have is order review, shipping address, payment information, and a model. So literally four more things and they're really small, we've built a ton of forms already we can literally do each of these in one video and then we have the order review. So in all honesty we can be done in five videos or so, I'm going to say five to 10.
So let's go ahead and commit our code and hop into that next form in the next video.
Terminal
git status git add . git commit -m "implemented add to cart feature to add more cart products to a users cart"
Okay I'll see you in the next video.