Buupu
Buupu

Reputation: 77

Why isn't my array copying without reference in React?

I am making a web application to visualise path-finding algorithms using react. I currently have Dijkstra's algorithm implemented. However, when I passed a copy of my initial grid array to my pathfinding algorithm the original array gets modified.

import React, { useState } from "react";
import Node from "./Node";
import dijkstras from "../algorithms/dijkstras";

const START_NODE_ROW = 10;
const START_NODE_COL = 15;
const FINISH_NODE_ROW = 10;
const FINISH_NODE_COL = 35;

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

const createNode = (col, row) => {
  return {
    col,
    row,
    isStart: row === START_NODE_ROW && col === START_NODE_COL,
    isFinish: row === FINISH_NODE_ROW && col === FINISH_NODE_COL,
    distance: Infinity,
    isVisited: false,
    isWall: false,
    previousNode: null
  };
};

const Pathfinder = () => {
  const initialGrid = getGrid();
  const [grid, setGrid] = useState([...initialGrid]);

  const animatePath = visitedNodesInOrder => {
    for (let i = 0; i < visitedNodesInOrder.length; i++) {
      setTimeout(() => {
        const node = visitedNodesInOrder[i];
        const newGrid = grid.slice();
        const newNode = {
          ...node,
          isVisited: true
        };
        newGrid[node.row][node.col] = newNode;
        setGrid(newGrid);
      }, 100 * i);
    }
  };

  const visualizeDijkstras = () => {
    const tempGrid = [...grid];
    const startNode = tempGrid[START_NODE_ROW][START_NODE_COL];
    const finishNode = tempGrid[FINISH_NODE_ROW][FINISH_NODE_COL];
    const visitedNodesInOrder = dijkstras(tempGrid, startNode, finishNode);
    animatePath(visitedNodesInOrder);
  };

  return (
    <>
      <button onClick={() => visualizeDijkstras()}></button>
      <div className="grid">
        {grid.map((row, rowIndex) => {
          return (
            <div key={rowIndex}>
              {row.map((node, nodeIndex) => {
                const { isStart, isFinish, isVisited } = node;
                return (
                  <Node
                    key={nodeIndex}
                    isStart={isStart}
                    isFinish={isFinish}
                    isVisited={isVisited}
                  />
                );
              })}
            </div>
          );
        })}
      </div>
    </>
  );
};

export default Pathfinder;

Currently all nodes are set to visited on the first iteration of the animatePath() method because the nodes in the initial grid array have already been marked as visited by the dijkstras method. Despite me copying the initial array into the temp array and passing that to the path finding method.

Upvotes: 0

Views: 73

Answers (1)

Brian Thompson
Brian Thompson

Reputation: 14375

As stated in my comment, the issue is your copied array has nested arrays that point to their original references. So when you create a new array like this ...grid you're building your new array with references to the original sub-arrays.

The solution is to create new sub-arrays as well.

If the array is only 2 deep you can do something like this:

const tempGrid = [...grid.map.(subArray => [...subArray])];

Upvotes: 2

Related Questions