Akbar
Akbar

Reputation: 15

Changing class name of a div doesn't update it's appearance in React

I'm trying to toggle background of a div with changing className every second based on changing the state of a data array. As console.log(grid[0][0]) informs me, it actually changes the grid array data, but it doesn't update div after the first iteration. [I provided props wiith <App row={5} col={10}/> in index.js.]

import React, { useState, useEffect } from 'react';
import './App.css';

function App(props) {
  // Initializing the grid.
  let grid = initializeGrid(props.row, props.col);

  const [gridData, setGridData] = useState(grid);

  useEffect(() => {
    const interval = setInterval(() => {
      setGridData(gridData => updateGrid(gridData));
    }, 2000);
    return () => clearInterval(interval);
  }, []);

  return (
    <div className="container">
      {gridData.reduce(function (acc, itm, idx) {
        let item = itm.map((cell, index) => <div key={acc.length + index} className={cell.state ? "state-on" : "state-off"}>{acc.length + index}</div>);
        return acc.concat(item);
      }, [])}
    </div>
  );
}

function initializeGrid(row, col) {
  let cell = { state: false, count: 0 }
  let grid = [];
  for (let y = 0; y < row; y++) {
    grid.push([]);
    for (let x = 0; x < col; x++) {
      grid[y].push(cell);
    }
  }
  return grid;
}

function updateGrid(grid) {
  let currentState = grid[0][0].state;
  currentState ? (grid[0][0] = { state: false, count: 0 }) : (grid[0][0] = { state: true, count: 0 });
  console.log(grid[0][0]);
  return grid;
}

export default App;

App.css:

html, body, #root {
  box-sizing: border-box;
  background-color: #ffeead;
  height: 100%;
  padding: 10px;
  margin: 0px;
}

.container {
  height: 100%;
  display: grid;
  grid-gap: 3px;
  grid-template-columns: repeat(10, 80px);
  grid-template-rows: repeat(5, 80px);
  justify-content: center;
  align-content: center;
}

.container>div {
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 2em;
  color: #ffeead;
}

.state-off {
  background-color: #96ceb4;
}

.state-on {
  background-color: #ff6f69;
}

Upvotes: 1

Views: 460

Answers (1)

c0m1t
c0m1t

Reputation: 1242

You are mutating your state. Which is discouraged. In strict mode, updateGrid runs twice, so state of cell will toggle twice. Hence you see no changes.

updateGrid function should not mutate your state. It should be something like this:

function updateGrid(grid) {
  let currentState = grid[0][0].state;
  currentState
    ? (grid[0][0] = { state: false, count: 0 })
    : (grid[0][0] = { state: true, count: 0 });

  const grid0 = [{ ...grid[0][0], state: currentState }, ...grid[0].slice(1)];
  const newGrid = [grid0, ...grid.slice(1)];

  return newGrid;
}

codesandbox

Upvotes: 1

Related Questions