Home

Rebuilding Mercari's Search: Home & Menu

House Photo by Rowan Heuvel

This is the second post of the Rebuilding Mercari's Search series.

In this post, we'll talk about the home and the menu drafts. Before starting to implement the search, the filter, and the products list, I wanted to add a very simple home and a very simple menu to do the navigation between the home (url: /) and the search (url: /search) pages.

As we start to implement UI, I should tell you that my focus on this project was to do the logic, state management, and tests. This is why I was looking for a UI framework to work as my design system. With this idea, I don't need to work heavily with CSS.

I chose Material UI, because I'm familiar with it, so I can focus on other parts instead of learning a new framework now.

So let's install the library and start implement the home and the menu.

yarn add @material-ui/core

The home is just a page with a title for now as I want to focus on the navigation between the home and the search.

So the home, that will live in the / url, will have the menu to navigate to the search page, which will live in the /search url for now.

This is the home with the title:

export default function Home() {
  return <h1>Home</h1>;
}

This component page lives in the pages/index.tsx as NextJS does routing based on the folder and file structures.

To make all the pages have a menu to be able to navigate to other places, we need to add it to the pages/_app.tsx file. But to be able to do that, let's first implement our Menu component.

To simplify the menu at first, I wanted to add a button that will open or close the menu showing or hiding the menu items.

<Button aria-controls="menu" aria-haspopup="true" onClick={handleClick}>
  Open Menu
</Button>

This is the first part. Nothing much here. We need the handleClick function now.

const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);

const handleClick = (event: MouseEvent<HTMLButtonElement>) => {
  setAnchorEl(event.currentTarget);
};

The handleClick function only manage the state related to the anchorEl.

The rest of the menu UI is pretty simple, we only need to use the Menu and the MenuItem from the Material UI.

<MuiMenu
  id="menu"
  anchorEl={anchorEl}
  keepMounted
  open={Boolean(anchorEl)}
  onClose={handleClose}
>
  {menuItems.map((item: MenuItem) => (
    <Link href={item.linkTo} key={item.key}>
      <MuiMenuItem>{item.label}</MuiMenuItem>
    </Link>
  ))}
</MuiMenu>

We know about the anchorEl, but we need to implement the handleClose function, the menuItems list, and the MenuItem type.

The MenuItem is a "type" representation for each item:

export type MenuItem = {
  linkTo: string;
  label: string;
  key: string;
};

The menuItems is the simplest as it is just a list of items passed as a prop to this menu component. But we need to make sure it is passed and the "type" representation of this list is in the function component contract.

import { FunctionComponent } from 'react';

type MenuPropsType = { menuItems: MenuItem[] };

export const Menu: FunctionComponent<MenuPropsType> = ({ menuItems }) => {
    ...
};

And the handleClose function only undo what the handleClick does: reset the anchorEl with a null value.

const handleClose = (_: any) => {
  setAnchorEl(null);
};

Nice! The menu is not complete nor pretty, but it's functional now. We can start using in our app. To be able to reuse for all pages (for this app, it'll be for the home and the search pages), we just need to add it to the _app.tsx file.

import { Fragment } from 'react';
import type { AppProps } from 'next/app';
import Menu, { MenuItem } from 'Base/Layout/Menu';
import '../styles/globals.css';

const menuItems: MenuItem[] = [
  {
    linkTo: '/',
    label: 'Home',
    key: 'link-to-home',
  },
  {
    linkTo: '/search',
    label: 'Search',
    key: 'link-to-search',
  },
];

function App({ Component, pageProps }: AppProps) {
  return (
    <Fragment>
      <Menu menuItems={menuItems} />
      <Component {...pageProps} />
    </Fragment>
  );
}

export default App;

The Component is each page we want to create and we add the Menu at the top of the page. As we saw earlier, we need to pass the menuItems with the type contract we built in the menu. It's also nice that we can reuse the types to make the data consistent.

Final words

This was the second post of the Rebuilding Mercari's Search series and I hope this also provides value to you. In this post, we start creating the building blocks for the app by adding a very simple home and menu for navigation.

For the following post, we'll talk about the implementation of the search page, where we'll focus on the products list UI first.

Resources

Patreon Become a Patron Coffee icon Buy me a coffee