0

I am quite new to react and I am learning by trying to making an algorithm visualizer project. I am trying to make grid for shortest path algorithm where each node can be clicked to make a "wall". Since I have to dynamically change the grid on events, I tried to use the useState hook by react.

import './App.css';
import {useState} from "react";

const start_row = 9;
const start_col = 9;
const end_row = 20;
const end_col = 50;

function App() {

  const [darkMode, setDarkMode] = useState(true);

  function createNode(row, col) {
      return {row,
          col,
          isStart: row === start_row && col === start_col,
          isFinish: row === end_row && col === end_col,
          isMousePressed: false,

      };
  }

  const createGrid = (rows, cols) => {
        const grid = [];
        for (let row = 0; row < rows; row++) {
            const currentRow = [];
            for (let col = 0; col < cols; col++) {
                currentRow.push(createNode(row, col));
            }
            grid.push(currentRow);
        }
        return grid;
  }

  const initialGrid = createGrid(30, 65);
  let [grid, setGrid] = useState(initialGrid);


  const handleClick = () => {
      setDarkMode(!darkMode);
  }

  const setMode = (style) => {
      let backgroundColor, textColor, buttonColor;

      if (darkMode) {
          backgroundColor = "black";
          textColor = 'white';
          buttonColor = "#303030";
      } else {
          backgroundColor = 'white';
          textColor = 'black';
          buttonColor = "#ffe291";
      }

      if (style === 1) {
          return backgroundColor;
      } else if (style === 2) {
          return textColor;
      } else {
            return buttonColor;
        }
  }

  const drawNode = (node) => {
      if (node.isStart) {
          return <img src="https://img.icons8.com/ios-glyphs/30/null/play--v1.png"/>;
      }
      if (node.isFinish) {
          return <img src="https://img.icons8.com/ios-glyphs/30/null/finish-flag.png"/>
      }

      if (node.isMousePressed) {
         return <div className="Wall"></div>
      }
  }

  const nodeName = (row, col) => {
        return `node ${row}-${col}`;
  }

  const handleMouseDown = (row, col) => {
      let newGrid = grid.map((node) => {
            if (node.row === row && node.col === col) {
                node.isMousePressed = !node.isMousePressed;
            }
            return node;
      });
      setGrid(newGrid);
  }


  return (
      <div className="App" style={{backgroundColor: setMode(1), color: setMode(2)}}>
          <div className="header-container">
              <div className="darkmode-container">
                  <label className="darkmode-button" style={{backgroundColor: setMode(3)}}>

                      <input type="checkbox" className="darkmode-input" onClick={handleClick}></input>
                      <span className="darkmode-toggle">
                          <img className="moon" src="https://img.icons8.com/sf-regular/48/null/moon-symbol.png"/>
                      </span>
                      <img className="sun" src="https://img.icons8.com/material-outlined/24/000000/smiling-sun.png"/>

                  </label>
              </div>
              <div className="header">
                  <header>Visualizer</header>
              </div>
          </div>
          <div className="map-container">
              <div className="map">
                  {grid.map((row, rowIndex) => {
                      return (
                            row.map((column, columnIndex) => {
                                return (
                                    <div className={nodeName(rowIndex, columnIndex)} onClick={handleMouseDown(rowIndex, columnIndex) } >
                                        {drawNode(grid[rowIndex][columnIndex])}
                                    </div>
                                )
                            })
                      )
                  })}
              </div>
          </div>
      </div>

  );
}

export default App;

This is what I have so far and it simply crashes my app. The app works if I have a standalone grid variable not made by using "useState".

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
  • What is the error message? Too many rerenders? – Nick Parsons Nov 13 '22 at 04:21
  • Also, if you want your UI to reflect the updates to your `grid`, you need to call `setGrid()` when updating your array. Don't mutate your `grid` directly. See: [Updating Arrays in State](https://beta.reactjs.org/learn/updating-arrays-in-state) – Nick Parsons Nov 13 '22 at 04:33
  • @NickParsons Hi, yes that is indeed the error. I have edited the code to not mutate the grid itself and handle events. But the error still persists. – Varshith Meesala Nov 13 '22 at 10:57
  • You shouldn't be calling your function in the `onClick` either, it should be `onClick={() => handleMouseDown(rowIndex, columnIndex)}`. See [When to use onclick ={ myfuntion()} vs onclick={() => (myfunction())}](https://stackoverflow.com/q/70994125) – Nick Parsons Nov 13 '22 at 11:18

0 Answers0