- Read Tutorial
- Watch Guide Video
So let's go to actions and create a new file and let's call it shop.js
in here we want to not import some types yet, let's first just say export function and basically, we want to do the same thing we're doing in our user.js except for with different data. Okay, so export function and we'll say fetch shop categories right. And then in here we will basically just return or dispatch an action that is of type and we'll say, what do we want to call this? We'll say SET_SHOP_CATEGORIES
, and then the payload will be an array of types right, or categories.
So let's make a first object and it's going to have an ID of zero and we're going to have a title of, let's see what do we want to call it? We want to call it All right? We need that, we need All. Let's go look at what we have, like what categories we have. We have Javascript, UI/UX, Linux, Python, UML, and Ruby okay. So let's just copy this as many times as we need, and let's start naming these we have Javascript, UI/UX, I know we have Python in there and we have Ruby, I'm pretty sure I missed one. Linux and UML, okay we've got Linux right after UI/UX and then you UML after python, okay so we got UML and we got Linux.
Okay so get those in there, it shouldn't be too hard. And again I want you to get in the habit of thinking of this as like a response from a server. A server is always going to send you back data like JSON data. Okay so yeah that's our data right there, let's go ahead and IDs these, they have a unique ID. If we need it and because any mongoose model pretty much any database model is always gonna have an ID.
Okay, so SET_SHOP_CATEGORIES. Now we have to import SET_SHOP_CATEGORIES from ./types.
Okay, now what we need to do is we need to create this type, so let's go into types.js
, and let's put a comment, and let's say shop and let's say export constant SET_SHOP_CATEGORIES, okay sweet.
Now we have that, now we just need to call this and we need to hit a reducer with SET_SHOP_CATEGORIES so let's go create that reducer. Okay, so we have our reducers, let's create a new file and let's call this shopReducer.js
I'm going to close the style folder, just so you can see better. Okay now in here we want to do what we're doing in header navbar reducer, any one of these reducers. Mostly userReducer.js
because we're setting data but it's really straightforward.
Okay, first step is to import our actions so SET_SHOP_CATEGORIES is the only one that exists in here right now, from ../actions/types. Okay, sweet, get that in there, and then let's say export default function and this function is going to take in state and we're going to make an initial state constant and it's going to take in an action as well.
All right, so let's define the initial state. Let's say const INITIAL_STATE is equal to an object and that initial state is going to contain for now we're going to have categories right and that's going to be an empty array by default.
Alright now, what were going to do is we are going to do is type out a switch statement. All right switch statement javascript language basics, I don't know what it says I'm really curious now.
Okay, anyway action.type and then we want to switch the value of SET_SHOP_CATEGORIES. Alright and the reason we are structuring our application this way with reducers and actions and all that junk instead of just hard coding it in, like you might be wondering why don't we put the categories in the initial state? Why are we putting them in the action? Why don't we just skip the whole entire action step and put it in here? Or why don't we just skip all this action reducer redux stuff and put it directly in the shop right here like we're doing with headerLinks?
The reason is because we want to make it extremely structured right, we want to structure this very well so that when we fetch these from a database it as if we weren't like we are technically like we're assuming we pass from a database but that the ideas that were fetching these from a database and then we are setting them across our application okay.
And the reason we don't fetch this from a database is cuz it's pretty like we don't want to create a whole other action reducer just for the headerLinks like that's something that's not going to change too much. You're not going to really change the login button, obviously, you're going to change it based on whether the users logged in or not but you're never really going to be like oh I don't want this here I want it over here now, right.
If you want to make a change like that you would update the code and redeploy. But when it comes to categories it's like maybe you want to add more products to your e-commerce site right? You don't want to have to re-deploy just to add products, you want to be able to have another app or something that an admin can access or an admin dashboard on this app that the admin can just add in categories.
Now I probably explained that already, I know I've talked about it a bit but I want to make it crystal clear why we're doing it this way so you can actually learn and not just copy code. All right, so what we want to do is go to the shop reducer and do something with this shop categories really simple at this point you should know we want to map out state, and then we want to override categories.
Okay, now categories is going to be overridden with action.payload
because if you remember we are taking action.payload from here the payload is these objects, it's this array, okay we're replacing an empty array with this array, you see how there's a bracket there after payload and there's a bracket here at the bottom.
It's an array of objects as opposed to just an empty array, that's what we're doing. So you can think of the shop reducer as having an array like this right, and then we're just saying hey we want to get an array full of data that we've fetched from a server. Okay so again you're probably getting annoyed at this point that I'm explaining it so many times but we're fetching this data from a server we're mimicking it.
This obviously isn't a call to our backend but we're acting like this is the response. And if you've gone through the property management app which most of you probably have. We did this, we fetched it from a back end okay. So you should understand what's going on at this point and why we're doing it this way.
So shop reducer we're overwriting it, but we have to, okay it looks like we're getting it, I thought we weren't, and for the default, case make sure you just return state. We're never going to hit this default case but for some reason, you spelled this wrong or something in here. Well, even then it wouldn't because it wouldn't compile because we're typing it right here and that's the entire purpose of types. So you can do this really easily without having to break your code right.
Like for example, we could just use strings right. But then we might make a typo here and then in the actions, we might name it something else right, then it wouldn't hit it. So the reason we use type's is because it makes it extremely easy to basically have it work because if we tried to run this we'd get an error saying hey this doesn't exist if it had an extra s in it right.
Now if it was a string and it had an extra s in it, it would have no idea and you would assume that's a valid case right. Okay, so hopefully that makes sense. I don't think I can explain it much better at the moment but let's go ahead and close out of our reducer and let's close out of our action shop and I always forget but I just remembered we need to import it into our index.js
of our actions.
So let's go below user and let's say import and let's say what was it called, fetchShopCatagories
and then let's export it at the bottom. Notice how I'm using one export, you can do multiple exports but it doesn't matter. Let me show you, hold on, let's import it from shop, okay so basically what I'm saying is you can do this, you can do multiple exports.
And that might make it more readable for you because they're all coming from different imports so you might want to export them each in their own little export right. And that's perfectly fine if that makes it readable to you do that, like really do that. But the reason I'm doing it this way is because it's more readable to at least me. I think this is a more clean format and obviously, you can't import these all from the same file because they all exist in different files.
But they could all exist in shop like these could all be in shop but we choose to have them in specific files to make it really really clear. Imagine how messy it would be if we had all these user calls and all these shop ones on the same file all in our index.js, you could do that but it would be really gross. It would be messy and it'd be confusing.
For example, if you were another developer and you cloned this project and you had an assignment right. And they were like put the log in feature okay, we forgot to put in the sign in feature. That would be really messed up if they did forget to do that after a first deployment but say they had a sign in future like oh we didn't actually perform the get request or the post request to sign in.
You'd know where to go to implement that. You'd just be like okay it's in the user actions right. I forgot to implement sign it, or the auth actions for example or you might get an assignment like. "Okay, now that we have this built go ahead and modify this to take in another parameter, make it pass in a user id." You'd know to go exactly to shop. So it's an advantage if you clean up your code like this, it makes it super readable for other developers and even yourself in the future.
So now that I have that explained, let's go ahead and try it out, it should work. So we're in our shop.js file, let's say this.props.fetchShopCategories
and then we don't need to pass anything in. Now what's going to happen is it's going to set our shop categories into our state. Okay, it's not going to set our categories yet because we haven't setHeaderLinks okay. And there's a couple of catches here, so it's going to take a second to get fully working. We'll do it in this video but it's going to take a little bit of thinking.
So let's go ahead and make sure that's saved and let's open up our redux dev tools and I'm pretty sure we didn't put our shop in redux yet, so let's look at our chart. Okay so yeah I didn't do it yet, we only have user, headerNavbar, and form.
So let's head over to our index.js in reducers. All right let's import shop from './shopReducer';
and let's go after user here and just say shop, okay we're including it into our combineReducers call. You can think of rootReducer as like state and then it's like state.form, .user right and then from there, you can access your state within each one of these categories right.
So let's go ahead and look at this in the browser now, it looks like it messed up a bit, let's reload the page, and you'll see now we have state, shop, and then we have categories.
Now in categories, we have all of these categories, we have All, we have Javascript, we have UI/UX, Linux and so forth right. So what we need to do is basically set these as our headerLinks right. We need to get this categories information into the navbarLinks okay, navbarLinks is empty we need to get it into there.
Now I didn't even think about this but since it is categories we can set it directly from our reducer okay, or directly from our actions. We don't even have to dispatch it to the shop, we can just dispatch it straight to navbarLinks and then throw it in there right. But the only problem with that is that it's not modeled yet to be the way we need it.
So let me show you what I mean. Okay, so we're going to keep the shopReducer because we still need it but we don't really need to be setting it in here. So what I want to do is I want to comment out this action type right, and I want to comment out this SET_SHOT_CATEGORIES and then I want to go into our shop.js in actions and comment that out and then instead of importing that let's import SET_NAVBAR_LINKS.
Okay so this might get a little bit confusing since we're using navbarLinks in shop and not in headernavbar so it might even be a good idea to put this into our header navbar but it's part of the shop so it doesn't really matter. Just go ahead and say SET_NAVBAR_LINKS and then now what's going to happen is it's going to set our navbarLinks, it's going to go to our reducer our headernavbarReducer and it's going to hit this and set the navbarLinks.
Now there's going to be a catch with this and it's that we don't have all the properties we need, but we can easily change our model to do that. Okay so let's go ahead and see what happens because I know we have a title in there so it might work a little bit. See it set's the title.
Let's go ahead and reload this and look in here and see what it's looking like. Okay, we've got our navbarLinks in our navbarLinks, see how it's no longer in our categories? So that's the idea, we could set it in categories if you want just so you can have like okay we've got categories in our shop they also existing here but it doesn't matter.
Feel free to do whatever you think is cleanest and clearest to you and whoever you might be working with if you were to work on this with another person. Okay, so we're setting the bar links, now we just need to reference wherever basically we need to figure out what we want to do with these okay, we don't just want an id and title, we want to be able to click on these right. We want to be able to say hey let's click on this and filter our items. Isn't that awesome how it just works automatically? We didn't even have to write a component for that we just had to set the data, really awesome.
So basically what we need to do is pass in a custom onClick okay, because if we go back let's go to navbar.js
. In navbar.js we have an onClick that's just saying changeNavbarActive with the ID. Okay, and that's an action okay, and that's all good except for we want to be able to filter our items as well.
So what we need to do is we need to basically pass in a custom property right, we have title and stuff right. So what we need to do is we need to pass in another onClick, but real quick, you see how it says link.active? We don't even have that in our model but since we've been clicking them we might now in our redux devtools, let me show you what I mean. Do you see how it says active now?
We basically added that property to our model. So it doesn't even matter that the model is wrong, it's going to automatically add it. And the reason it automatically adds it is because if you remember how we're setting that we go through our navbarReducer right, and we set these to true or false all right. So if it doesn't have one it just immediately set's it to false anyway. And then if the ID matches up it'll set it to true. Okay, so that's how that's working.
Feel free to add it in the shop.js in the actions if you want, you can add an active property but it doesn't matter obviously. Okay so let's go ahead and think about this, we need another property in here that will basically allow us to filter what products we're seeing okay. Now the products are going to have basically the title, they are basically going to say belongs to and then it's going to have a title okay, or an id. Typically you'd have an ID like on the back end you'd have an ID, it would just say hey it belongs to the navbarLink or it belongs to the category with ID 1 right or id 2.
So what we need to do is we need to say when we click on this item we want to basically set a property, we want to set something in our shop right, we want to set a variable in our shopReducer saying selected category id. And then what we can do is we can say okay let's put zero because we want it to by default be selected to all, right, wherever that went, let's see if I can move this back.
We want it by default to be selected to all so that's the id we want. And then we'll filter it in the reducer based on that. So we need a place to store the filtered categories or filter products, so we want to say products selected right, productsThatBelongTo or something like that.
Let's just say productsSelected and that's going to be an array that we're going to override and basically just fill in with products that have this ID in their array. So before we get into this it's going to get really confusing if it hasn't already unless we build out the fetch products. We want to get the products in there, we want to make the model for the products so we can see kind of how this will work.
So let's go ahead and commit our code.
Terminal
git status git add . git commit -m "developed shopReducer and fetch shop categories, action creator"
Okay, I'll see you in the next guide.