Part 2: Build This Cool Dropdown Menu With React, React Router and CSS

Jason Melton
The Startup
Published in
6 min readSep 27, 2020

--

After my last blog about building a ~cool~ dropdown menu, I received the suggestion to write a part 2.

Andrew Bone pointed out, “Generally, when making a component, the aim is to make it reusable and simple enough that it rarely needs to be revisited.”

I took the advice to heart. In the following, I show how I refactored my dropdown menu to be just this: reusable and simple.

jump to the code on GitHub

Tutorial

The goal: take the previous dropdown menu and rewrite the code so it uses any JSON object of menu data to create a dropdown with the same structure and styles as the original.

Table of Contents

  • Preliminary Junk
  • Mapping a JSON Object
  • Dynamic Styles
  • Dynamic Routes
  • Conclusion

Preliminary Junk

To start, I duplicated the original repository and added a JSON file with some dummy data.

Mapping a JSON Object

In order to make the component dynamic, I use map(). Map is a common tool employed in React apps as it can transform an indefinitely sized array of items into JSX. This allows components to be defined abstractly making them reusable.

Our original Menu component looked like this:

As you can see, I have each item spelled out with its own div and settings. In the refactored version, I instead use JSX to render the return of mapping the JSON object.

The return looks like this:

I keep the initial menu item in its own div. It will display when the menu is closed and the other menu items will hide behind it. Beneath that, I call the renderMenuItems() function which takes a JSON object as a parameter.

renderMenuItems() is complicated. I will show the whole function and explain it piece by piece.

I will explain colorArr, colorCounter, and itemStyle in the next section.

First, notice line 27. On this line, I return a map() of data, the JSON object parameter. map() runs a callback on each item of an array, returning the result of that function in a new array.

map() can take two parameters. The first parameter is the item from the array. I labeled them item. The second is each item’s index, labeled index.

Next, see line 39. On this line, I return dynamic JSX for each item in the map(). These will be the divs of our menu items. Each item has an id, name, and route.

I give them each div the m-item classname, unchanged from the original. They get an onClick event that triggers pushToRoute(). Also the same as the original except the parameter is in the JSON object under route. Each gets a key of the JSON’s id. Finally, I display the JSON object’s name as text in the div.

This will dynamically render as many menu items as there are in the JSON object sent to this component.

Dynamic Styles

CSS controls the dropdown to work properly. In my original menu, I used a function called setClassNames() to add classnames to the items. Then, I spelled out an individual classname for each item and the specific length I wanted them to drop to.

While this functioned correctly, it was not easily reusable. Not only would I have to spell out a new open-# for each additional item, I also use a lot of extra code.

Since I am now using map() on the menu items, I can work out the styles as I go. There are two parts to the CSS:

  1. A top set to a size of 1.8em times the number item it is on the list (1.8, 3.6, 5.4, 7.2, etc.).
  2. One of three color hexes set as a background-color (#9b5de5, #f15bb5, #00BBF9).

Take a look at renderMenuItems one more time.

React allows me to add styles to a div as an object written in camelcase syntax of JavaScript.

Notice on line 35, I set the top. I use the map() index parameter to add a dynamically increasing em size.

The background-color is a little trickier. I set up an array called colorArr with my 3 color hexes in it. To access these, I set up a counter called colorCounter that I will use to access the colors.

The colorCounter is initially set to -1. On line 31 inside the map(), I run a ternary where if the counter is less than 2, I add 1 to the counter. If it is over 2, I reset the counter to 0. Thus, the counter will run 0, 1, 2, 0, 1, 2… for as long as the map() goes.

On line 36, I set the “backgroundColor” to colorArr[colorCounter]. This provides the sequence of colors for the menu items.

Finally, I need to add the top and background-color properties to the items based on when the top menu item is clicked.

When clicked, the top menu item toggles openMenu, a useState hook, between true and false.

On line 42, the style property of the div accepts JSX. I use a ternary here to return the object containing the new top and background-color if openMenu is true. If false, it receives a null.

Dynamic Routes

The final piece of this is to go back to my Switch statement and render the routes dynamically as well. I can map() the same JSON object in order to set up the corresponding route of each menu item. You can find that on line 25.

Again, what’s missing here are the actual components of the the app that this menu would be applied to. This could be solved by either altering the JSON to include the component’s name or maybe to set up a lookup table that corresponds components to the IDs in the JSON. Something like that.

Conclusion

It was great to revisit my code and improve on my earlier ideas. Again, thanks to Andrew Bone for challenging me to try this. I feel like I created a much more flexible, reusable tool the second time around.

If you have any feedback or suggestions, please reach out. Comment or email me at jason.melton2@gmail.com. Regardless of that, thanks for reading. Best, Jason.

--

--