React JS Interview Questions ( Grid Lights - GreatFrontEnd ) - Frontend Coding Interview

React JS Interview Questions ( Grid Lights - GreatFrontEnd ) - Frontend Coding Interview

Table of contents

Grid Lights is a famous problem from GreatFrontend.com which has been asked in Machine Coding round of Frontend Interviews at companies like Meta, Google, Netflix, Amazon, Airbnb, etc. In this blog, I will provide the solution to the problem

Problem Statement

Build a grid of light cells where you can click on cells to activate them, turning them green. When all the cells are activated, all the cells will be deactivated one by one in the reverse order they were activated with 300ms interval in between them.

Steps:

  1. Create a grid

  2. Create the cell and style it with a green background color when activated.

  3. Add click logic to activate cell when clicked.

  4. In the click logic, when all the cells are activated, deactivate cells one by one using setInterval.

import "./styles.css";
import { useState } from "react";

const Cell = ({ filled, onClick, isDisabled, label }) => {
  return (
    <button
      type="button"
      className={filled ? "cell cell-active" : "cell"}
      onClick={onClick}
      disabled={isDisabled}
      aria-label={label}
    />
  );
};

export default function App() {
  // order state for order of activated cells 
  const [order, setOrder] = useState([]);
  const [isDeactivating, setIsDeactivating] = useState(false);
  const config = [
    [1, 1, 1],
    [1, 0, 1],
    [1, 1, 1]
  ];
  const activateCells = (index) => {
    const updatedOrder = [...order, index];
    setOrder(updatedOrder);
    if (updatedOrder.length === config.flat(1).filter(Boolean).length) {
      // reverse the animation
      deactivateCells();
    }
  };
  const deactivateCells = () => {
    setIsDeactivating(true);
    const timer = setInterval(() => {
      setOrder((currentOrder) => {
        // create a shallow copy of the order state array
        const newOrder = currentOrder.slice();
        newOrder.pop();
        if (newOrder.length === 0) {
          clearInterval(timer);
          setIsDeactivating(false);
        }
        return newOrder;
      });
    }, 300);
  };
  return (
    <div className="wrapper">
      <div
        className="grid"
        style={{
          gridTemplateColumns: `repeat(${config[0].length}, 1fr)`
        }}
      >
        {config
          .flat(1)
          .map((value, index) =>
            value === 1 ? (
              <Cell
                key={index}
                filled={order.includes(index)}
                onClick={() => activateCells(index)}
                isDisabled={order.includes(index) || isDeactivating}
                label={`Cell ${index}`}
              />
            ) : (
              <span />
            )
          )}
      </div>
    </div>
  );
}
.wrapper {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 16px;
}
.grid {
  display: grid;
  max-width: 300px;
  width: 100%;
  gap: 16px;
  border: 1px solid black;
  padding: 20px;
}

.cell {
  height: 0;
  padding-bottom: 100%;
  border: 1px solid black;
  background-color: transparent;
}

.cell-active {
  background-color: green;
}

That's how we solved this problem. If you didn't understand something, please do comment I will try to answer your queries in the comments.

If you liked the problem and want me to write a blog/provide solutions to similar problems, please hit the like button and share it with someone who is preparing for frontend interviews.

Like. Comment. Share.