Как сохранить предыдущее состояние 2D-массива?

#reactjs #use-state

Вопрос:

Я хочу иметь возможность вносить изменения в 2D-массив, но иметь возможность сохранять предыдущее состояние для последующего использования.

Например:

Первый щелчок: prevArray = [] currArray = [1,0,0],

Второй щелчок: prevArray = [1,0,0] currArray = [1,1,0],

Третий щелчок: prevArray = [1,1,0] currArray = [1,1,1]

  import { useState, useEffect, useRef } from "react";
import "./App.css";

function App() {
  const numRows = 3;
  const numCol = 3;

  const [currentGrid, setCurrentGrid] = useState(() =>
    Array.from({ length: numRows }).map(() =>
      Array.from({ length: numCol }).fill(0)
    )
  );

  const prevGrid = usePrevious(currentGrid);

  function usePrevious(value) {
    const ref = useRef();
    useEffect(() => {
      ref.current = value;
    }, [value]);
    return ref.current;
  }

  const gridClick = (i, k) => {
    const newGridState = [...currentGrid];
    if (newGridState[i][k] === 1) {
      newGridState[i][k] = 0;
    } else {
      newGridState[i][k] = 1;
    }
    setCurrentGrid([...newGridState]);
  };

  return (
    <>
      <div
        className="grid"
        style={{
          display: "grid",
          gridTemplateColumns: `repeat(${numRows},20px)`,
          marginBottom: "20px",
        }}
      >
        {currentGrid.map((rows, i) =>
          rows.map((col, k) => (
            <div
              onClick={() => gridClick(i, k)}
              style={{
                width: 20,
                height: 20,
                backgroundColor: currentGrid[i][k] ? "blue" : "green",
                border: "solid 1px black",
              }}
            ></div>
          ))
        )}
      </div>

      <div
        className="grid"
        style={{
          display: "grid",
          gridTemplateColumns: `repeat(${numRows},20px)`,
          marginBottom: "20px",
        }}
      >
        {prevGrid != null
          ? prevGrid.map((rows, i) =>
              rows.map((col, k) => (
                <div
                  style={{
                    width: 20,
                    height: 20,
                    backgroundColor: currentGrid[i][k] ? "blue" : "green",
                    border: "solid 1px black",
                  }}
                ></div>
              ))
            )
          : console.log("empty")}
      </div>
    </>
  );
}

export default App;
 

В настоящее время состояние использования «prevGrid» просто копирует те же значения, которые находятся в «currentGrid».

Комментарии:

1. Вы должны переместить свой onClick обработчик вверх, чтобы он стал константой функции. Как есть, новая копия функции создается на каждой итерации карты.

Ответ №1:

Вы можете использовать какой-нибудь крючок, как в этом примере из useHooks.

В этом примере они использовали для получения предыдущего значения переменной счетчика:

 import { useState, useEffect, useRef } from "react";

// Usage
function App() {
  // State value and setter for our example
  const [count, setCount] = useState(0);

  // Get the previous value (was passed into hook on last render)
  const prevCount = usePrevious(count);

  // Display both current and previous count value
  return (
    <div>
      <h1>
        Now: {count}, before: {prevCount}
      </h1>
      <button onClick={() => setCount(count   1)}>Increment</button>
    </div>
  );
}

// Hook
function usePrevious(value) {
  // The ref object is a generic container whose current property is mutable ...
  // ... and can hold any value, similar to an instance property on a class
  const ref = useRef();

  // Store current value in ref
  useEffect(() => {
    ref.current = value;
  }, [value]); // Only re-run if value changes

  // Return previous value (happens before update in useEffect above)
  return ref.current;
}
 

Комментарии:

1. Я внес изменения на основе вашего комментария (как видно из моего недавнего редактирования). Но все равно «prevGrid» отражает текущее состояние как «currentGrid». Может ли это иметь какое-то отношение к тому, как я обновляю текущую сетку? Вот ссылка на код в песочнице: codesandbox.io/s/damp-https-ikqiz .