FTC Notice: We earn commissions when you shop through the links on this site.

Matt

How to create a react memory game

Memory games are a fantastic way to practice your React skills while building something fun! In this tutorial, we’ll guide you through creating your own memory game from scratch using React.

Prerequisites

  • Familiarity with basic React concepts (components, props, state, JSX).
  • Some CSS knowledge for styling (we’ll provide basic examples).

Project Setup

  1. Create a new React project:

    Bash
    npx create-react-app memory-game
    
  2. Structure your project:

    src/
      components/
        Card.js
        GameBoard.js
      App.js
      styles.css
    

Building the Game

Click here for my favorite React reference book 

1. Data and Card Component

  • Card Data Structure (in Card.js)

    JavaScript
    const Card = ({ id, image, isFlipped, isMatched, handleClick }) => {
      return (
        <div 
          className={`card ${isFlipped ? 'flipped' : ''} ${isMatched ? 'matched' : ''}`}
          onClick={() => handleClick(id)}
        >
          <div className="front">{/* Placeholder for a question mark or back image */}</div> 
          <div className="back">
            <img src={image} alt="Card Content" /> 
          </div>
        </div>
      );
    };
    
    export default Card;
    
  • Explanation:

    • Each card has idimage, and flags for isFlipped and isMatched.
    • We use CSS classes for styling the different states of the card.

2. Game Board and Rendering

JavaScript
// In GameBoard.js
import React, { useState, useEffect } from 'react';
import Card from './Card';
import shuffle from 'lodash.shuffle'; // Or your own shuffle function

const GameBoard = () => {
  const [cards, setCards] = useState(shuffleCards()); // We'll define shuffleCards later
  const [flippedCards, setFlippedCards] = useState([]);
  const [matchedCards, setMatchedCards] = useState([]);

  // ... Code for handleClick, checking matches (from previous examples)

  // Function to generate and shuffle card data
  const shuffleCards = () => {
    // ... Add your logic to create card objects with images  
  }

  return (
    <div className="game-board">
      {cards.map((card) => (
        <Card 
          key={card.id} 
          {...card} 
          handleClick={handleClick} 
        />
      ))}
    </div>
  );
};

export default GameBoard;

3. Core Game Logic (Explained in Previous Examples)

  • handleClick (prevents invalid clicks, adds card ID to flippedCards)
  • useEffect (checks for matches, updates matchedCards, resets flippedCards)

4. Styling (styles.css):

CSS
.game-board {
  display: grid;
  grid-template-columns: repeat(4, 1fr); /* Adjust for grid size */
}

.card { 
  /* Add styles for the card container */
}

.flipped {
  /* Styles for when the card is flipped */
}

.matched {
  /* Styles to indicate matched cards */
}

5. Win Condition, Restart, Additional Features (Choose one or two)

Deployment (Briefly mention options)

Conclusion

Congratulations on building your memory game! Try customizing its looks, adding difficulty levels, timers, or other fun features!

How to use the Object-Fit Property in CSS

In web design, properly presenting images and videos across different devices can be a challenge. You have likely encountered the “squished image” problem—where a CMS or user uploads a portrait photo, but your design demands a landscape box.

This is where the CSS object-fit property becomes a game-changer. It allows developers to control how <img> or <video> elements resize to fit into their containers, much like background-size works for background images.

Whether you need to maintain aspect ratios, fill specific cards without distortion, or manage responsive layouts, object-fit is your go-to solution.

Quick Sample

Portrait

Portrait Source

Landscape

Landscape Source

Tiny

Tiny Source

The Syntax

The syntax is straightforward. However, for object-fit to work, the element usually needs a defined height and width on the container or the image itself to reference.

CSS

img {
  width: 100%;
  height: 300px; /* Force a specific height */
  object-fit: value; 
}

Here, value can be one of the following:

  • fill

  • contain

  • cover

  • none

  • scale-down

Exploring Object-Fit Values

Let’s look at how a landscape image behaves inside a square container using these different values.

Value What it does Best Use Case
fill (Default) Stretches the content to match the container width and height perfectly. This often leads to distortion (squished images). Rarely used, unless distortion is an artistic choice.
contain Scales the content to fit the container while preserving aspect ratio. The whole image is visible, but empty space (letterboxing) may appear. Product images or data visualizations where seeing the entire image is mandatory.
cover Resizes the image to cover the entire container while maintaining aspect ratio. The edges of the image are clipped (cropped) to fit. Hero banners, user avatars, and card thumbnails.
none Ignores the container size and displays the image at its original resolution. Patterned backgrounds or specific decorative elements.
scale-down Compares none and contain and selects whichever results in the smaller image. Icons or logos that should never be upscaled and pixelated.

Practical Examples

1. The “Card Component” (Using cover)

Imagine you have a grid of blog cards. You want a uniform look (square images), but the source images are all different shapes.

HTML:

HTML

<div class="card">
  <img src="sunset.jpg" alt="Beautiful Landscape">
</div>

CSS:

CSS

.card img {
  width: 100%;    /* Fill the width */
  height: 200px;  /* Force a square height */
  object-fit: cover; 
}

The Result: The image fills the 200px square perfectly. It maintains its aspect ratio, simply cropping off the sides that don’t fit. No squishing!

2. The “Product Lightbox” (Using contain)

For situations where you must ensure the user sees the whole image—like a product detail page—you don’t want any cropping.

CSS Adjustment:

CSS

.container img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  background-color: #f4f4f4; /* Optional: fills the empty space */
}

The Result: The image scales down until it fits. If the aspect ratios don’t match, the remaining space is left empty (or filled with a background color), ensuring no part of the product is hidden.


Level Up: Controlling the Crop with object-position

When you use object-fit: cover, the browser defaults to cropping the image from the center. But what if the subject of your photo (like a person’s face) is at the very top?

You can pair object-fit with the object-position property to shift the focus.

CSS

.avatar {
  width: 100px;
  height: 100px;
  border-radius: 50%;
  object-fit: cover;
  object-position: top center; /* Anchors the image to the top */
}

This ensures that if cropping occurs, it keeps the top of the image (the face) and crops the bottom.

Conclusion

The object-fit property is a powerful tool in the CSS toolkit, enabling developers to create visually consistent websites without relying on complex background-image hacks. If you want to learn more about images and how it impacts speed, this post on image optimization might be of interest.

  • Use cover for layout consistency (cards, heroes, backgrounds).

  • Use contain for content integrity (products, logos).

Experiment with object-fit and object-position in your next project to instantly improve your responsive image handling.

Prettier Code Formatter Setup Guide

Prettier is more than just a code formatterit’s a powerful tool that brings unified code presentation to your projects. By automating code styling, Prettier not only saves time but also eases collaboration across teams. Supporting a wide array of languages and seamlessly integrating with popular editors, Prettier ensures that your code is consistent.

Why Prettier?

  • Unified Code Presentation: Eliminate debates over code style by adopting a consistent format across your entire project.
  • Reduced Styling Discussions: Spend less time arguing about code styling and more time focusing on functionality.
  • Wide Language Support: From JavaScript to TypeScript, HTML, CSS, and beyond, Prettier supports multiple languages.
  • Editor Integrations: Easily integrates with most popular editors, so your code looks great everywhere.

Installation and Initial Setup

Click here to deploy, manage, and scale cloud applications EASY with $200 credit

Before you can enjoy the benefits of Prettier, you need to install it in your project. For Node.js projects, you can add Prettier as a development dependency.

Using npm

bash

Copy

npm install –save-dev prettier

Using Yarn

bash

Copy

yarn add –dev prettier

Configuring Prettier for Your Project

After installation, create a .prettierrc file in your project’s root directory. This file allows you to specify your formatting preferences. Below is an example configuration:

json

Copy

{

semi”: false,

tabWidth“: 2,

printWidth“: 80,

singleQuote“: true,

trailingComma“:es5″,

jsxSingleQuote”: true,

bracketSpacing“: true,

  “jsxBracketSameLine”: false,

arrowParens”:avoid“,

endOfLine“:lf”

}

Explanation of Key Options

  • semi: Set to false to omit semicolons at the end of statements.
  • tabWidth: Specifies the number of spaces per indentation level.
  • printWidth: Determines the maximum line length where Prettier will attempt to wrap code.
  • singleQuote: Uses single quotes instead of double quotes.
  • trailingComma: Configured as es5 to add trailing commas in ES5-compatible code, reducing version control diffs.
  • jsxSingleQuote: Uses single quotes for JSX attributes.
  • bracketSpacing: Controls the spacing between brackets in object literals and arrays.
  • jsxBracketSameLine: When false, keeps the closing JSX tag on a new line for better readability.
  • arrowParens: Set to avoid to omit parentheses around single-argument arrow functions.
  • endOfLine: Enforces consistent line endings, e.g., lf for Unix-like systems.

Integrating Prettier into Your Workflow

Integrate Prettier into your development workflow to ensure consistency throughout your project. You can add a script in your package.json to format your codebase:

json

Copy

“scripts”: {

format”:prettier –write .”

}

Run this script with:

bash

Copy

npm run format

This command will automatically format all supported files in your project, keeping your code clean and consistent.

Customizing Prettier for Different Scenarios

Remember, Prettier’s configuration is highly customizable. Adjust the settings in your .prettierrc file based on your project’s needs, team conventions, or personal preferences. The flexibility of Prettier allows you to create a codebase that meets your specific style requirements while ensuring the overall consistency of the code.

Get Started Today

Click here to deploy, manage, and scale cloud applications EASY with $200 credit

By integrating Prettier into your project, you streamline code formatting, improve code readability, and enhance collaboration. Ready to take the next step in your development journey?

Experiment with these configurations and see how Prettier can transform your coding workflow—leaving more time for what really matters: building great software.

Conclusion

Prettier is not just about formatting code; it’s about creating a unified development environment that minimizes style debates and enhances collaboration. With straightforward installation, simple configuration, and powerful integration options, Prettier is an essential tool for any modern development project. Embrace Prettier and watch your codebase become more consistent, easier to read, and a pleasure to work with.