How to Give a Navbar Component Functionality
All right, let's go ahead and develop an action to basically make it so we can hit our reducer and change which one is active.
Guide Tasks
  • Read Tutorial
  • Watch Guide Video
Video locked
This video is viewable to users with a Bottega Bootcamp license

So I'm going to close the terminal here and I'm going to go into types.js and I'm going to export another type. Let's call it CHANGE_ACTIVE and we'll say it is equal to CHANGE_ACTIVE_NAVBAR let's call it CHANGE_NAVBAR_ACTIVE to be more consistent with SET_NAVBAR okay. All right let's go into our actions in headernavbar.js.

First things first, let's import it and change active.

headernavbar.js

import {
    SET_HEADER_LINKS,
    SET_NAVBAR_LINKS,
    CHANGE_NAVBAR_ACTIVE
} from './types';

Then let's copy this function, and let's call it changeNavbarActive let's pass in an ID rather than links, and let's return a type of CHANGE_NAVBAR_ACTIVE and let's make the payload the id.

export function changeNavbarActive(_id) {
    return ({
        type: CHANGE_NAVBAR_ACTIVE,
        payload: _id
    })
}

Now what we need to do is to go into index.js and import it and export it. So copy this title(changeNavbarActive) go into index.js and import it from headerNavbar and export it from this file.

index.js

import {
    setHeaderLinks,
    setNavbarLinks,
    changeNavbarActive
} from './headernavbar';

export {
    setHeaderLinks,
    setNavbarLinks,
    changeNavbarActive
};

Okay, now we have access to the action. Now what we need to do is actually create the reducer to handle this. Let's go in here and let's create an additional case and let's call it CHANGE_NAVBAR_ACTIVE and import that. Okay, we have SET_HEADER, SET_NAVBAR, and CHANGE_NAVBAR, import that type.

headernavbarReducer.js

import {
    SET_HEADER_LINKS,
    SET_NAVBAR_LINKS,
    CHANGE_NAVBAR_ACTIVE
} from '../actions/types';

In here, we want to basically return state, except for we want to return a new set of navbar links. We want to modify it, we want to return the same navbar links except for with the selected ID. We want that object to be true. Okay, so basically in account.js we want to take this information and say hey if the ID matches up, set active to true and then on the rest of them just set them all to false. That way when we have multiple items it will set only that one to true and then it will set the rest to false.

So let's go in here and let's just say const navbarLinks is equal to navbarLinks. here let's read up on this I want to use the correct one okay. So I'm going to go to javascript map function I'm googling it and we're going to use this one or forEach.

Okay, so it says this method creates a new array with the results of calling a provided function on every element in the calling array. So basically we want to use this one because we want to create a new one. The reason we don't want to use forEach, I'll click on that is because it executes a provided function once for each array element.

large

Basically what it's doing is, if we were to modify the data in here it would modify the array and we know in react that we're not supposed to modify state we're supposed to create a new copy of state so what we need to do is we need to use map because it's going to create a new array for us, we want to create a new array, we want to copy existing state we don't want to use the same state again, we want to set a new object.

So let's navbarLinks is equal to navbarLinks.map we'll say link, and what we'll do is we'll set them all to false so link.active is equal to false, and then we'll say if link.id is equal to action.payload which we know is the ID because we passed it in with our action. Then we will set this one to true and since we have already set everything else to false everything will be false except for this one.

headernavbarReducer.js

case CHANGE_NAVBAR_ACTIVE:
    const navbarLinks = navbarLinks.map(link => {
        link.active = false;
        if(link._id == action.payload) {
            link.active = true;
        }
    })
    return {
        ...state,
        navbarLinks
    }

Now we can return it and we should be good.

Let's go try this out now, it should switch everything around, the colors should switch and so. So let's go into account.js and let's make sure everything's compiled, okay everything's working. Now we just need to make it so when we click this it calls that action. So let's go into our code and what we could do or what we have to do is go into navbar.js to do this.

Okay, and the onClick needs to not console.log this, what we need to do is say this.props. what was it? changeNavbarActive and then we need to pass in the ID. So we need to say link._id okay. So this.props.changeNavbarActive(link._id) and we're getting that ID from this link here.

large

And we're already using connect but we're not passing any actions so this won't work immediately, we need to say import * as actions from `../../actions'. Then what we need to do is go down here and put a comma after mapStateToProps and put the actions in. So really kind of basic stuff at this point, we've been doing this quite a bit and it should work, so let's go into Chrome and let's try it out.

large

Okay, it says cannot read property map of undefined, okay so we have an error. Lets go into our code lets reload this and try it again and then if we get that error we will fix it. Okay, it doesn't work, let's go into our code, and let's go into headernavbar.js changeNavbarActive, we're obviously hitting that because it's hitting this map which is breaking. So what we need to do is actually reference navbarLinks we're saying navbarLinks we're no saying state, so it has no idea what we're talking about, so we need to say state.navbarLinks.map.

Now let's try it. Okay it says cannot read property active of undefined, let's try this one more time cannot read property active of undefined.

large

Okay, let's try it, let's go into the code and see what's going on. Okay state.navbarLinks, so it should work but for some reason it's not. Let's link.active, let's go to account.js link.active, I wonder if for some reason we're mixing those up. What I want to do is I want to console log state.navbarLinks because it should have that data.

Okay, I clicked on it, it printed something before we got those errors and we do have our active. Oh I guess not, oh there it is. Active cannot read property active of undefined, interesting account.js line 36, let's check account.js line 36.

Okay, I know the problem here. We're returning an empty array so it's empty when it hits this and then it's breaking. So let's go to headernavbarReducer.js what we need to do is we need to return each link to this number of links or array that we're creating here. So at the bottom here let's say return link and that will be good.

Okay, let's try it out, it should be good, and we're Gucci. Okay look at that, it works great.

large

Okay, so lets go get rid of this console log and then we know this is working, so what we need to do now is we need to fix this up top. We need to add in the data here because clearly it's not rendering anything or passing in an empty array and we'll handle that in the next video. Let's go delete this console log in our reducer and commit our code.

Terminal

git status
git add .
git commit -m "finished navbar feature"

I'll see you in the next video.

Resources

Source code