Create a Memory Game with Next.js

Cover Photo

Cover photo by Dan Mall on Unsplash

As new technologies and frameworks evolve, we start to get curious about it. When we first get contact with very early stage ones, eventually we could get the wrong idea about it as their concepts are not fully evolved and the integration and API is also not fully stable. And after those technologies grow it is possible to get a better perspective of them.

With that in mind, I wanted to experiment again with Next.js after some time since I first jot with it, some years ago. As a starting point I wanted to do something that I could use and present to others without saying “You know, it is just a test project so it won’t work for X, Y and Z”.

After some consideration, I wanted to create a simple Memory Game.

Setting up the project

I have to say that Next.js has lots of configurations out-of-the-box that were very handy, just running their own standalone app. As mentioned at their official doc, just run

npx create-next-app@latest

And their standalone will ask you things about how do you want to code and your project structure. For me, It was very handy as I wanted to use things like:

That’s it. Run the project locally with yarn dev and access your localhost:3000.

Creating the Page Elements

The integration between how the project is structured and how the routing works is also a plus. It is very similar to what Remix framework did (just saw there first, don’t know who started it!). It is not needed to setup a router as your “folders are your router”. That’s how it felt to me.

Then I just created the first elements, the <Board /> component and its <Card /> component to present the cards.

In order to create some “moviment” I added some transitions and control them with state out of the <Card /> component. A hook called useGame() that is responsible for storing the logic of the game was created.

Game Logic

After creating the page elements, the logic code must be created. As mentioned before, the hook useGame() was created and inside of it, after creating several states with useState() I just notice that this is a use case for the useReducer().

export function useGame() {
  const [game, dispatchGame] = useReducer(gameReducer, initialGameState);

  /* ... */

  return {
    state: {
      ...game,
    },
    handler: {
      revealCard,
      reset,
    }
  }
}

There are some handlers and the game state that can be accessed by the Page and its components. The state nformaion provided by this hook is:

  • the list of cards (already shuffled)
  • the list of found cards
  • the list of revealedIndexes from the actual screen
  • and the moves counter

And the handlers are:

  • one callback to reveal a specific card based on its index
  • one callback to reset the game

The game result is decided using the util function isGameOver(), when all cards have been found.

Final Thoughts

It was nice to understand some of the concepts used by Next.js such as their router and the frameworkd itself. Also, how those learnings translate and impact the developer experience while creating an app made me realize that Next.js is actually a good option to bootstrap a project nowadays.

Parallel to that, it was also nice to exercise some of the ReactJS knowledge and how to test it using React Testing Library + Jest.

The final project to be live-tested at memory.caian.dev, and the code is provided at this GitHub repo.