admin管理员组

文章数量:1279234

I have the following function:

import React, { useState } from "react";

const Sheet = () => {
  const [matrix, setMatrix] = useState([
    [null, null, null],
    [null, null, null],
    [null, null, null]
  ]);

  const handleChange = (row, column, event) => {
    let copy = [...matrix];
    copy[row][column] = +event.target.value;
    setMatrix(copy);

    console.log(matrix);
  };

  return (
    <div className="sheet">
      <table>
        <tbody>
          {matrix.map((row, rowIndex) => (
            <tr key={rowIndex}>
              {row.map((column, columnIndex) => (
                <td key={columnIndex}>
                  <input
                    type="number"
                    onChange={e => handleChange(rowIndex, columnIndex, e)}
                  />
                </td>
              ))}
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
};

export default Sheet;

This works, but this is always for a 3x3 matrix. I have to set this dynamic, so I thought I'll set the default state with ES6 array construction like:

const n = 4; // Will be set through props
const [matrix, setMatrix] = useState(Array(n).fill(Array(n).fill(null)));

But when I use this case and I update (type a number in an input field), the whole column in the matrix will get that number.

Can anybody explain this?

When I use this piece of code:

const [matrix, setMatrix] = useState(
    Array.from({ length: 3 }, v => Array.from({ length: 3 }, v => null))
  );

it works again.

I have the following function:

import React, { useState } from "react";

const Sheet = () => {
  const [matrix, setMatrix] = useState([
    [null, null, null],
    [null, null, null],
    [null, null, null]
  ]);

  const handleChange = (row, column, event) => {
    let copy = [...matrix];
    copy[row][column] = +event.target.value;
    setMatrix(copy);

    console.log(matrix);
  };

  return (
    <div className="sheet">
      <table>
        <tbody>
          {matrix.map((row, rowIndex) => (
            <tr key={rowIndex}>
              {row.map((column, columnIndex) => (
                <td key={columnIndex}>
                  <input
                    type="number"
                    onChange={e => handleChange(rowIndex, columnIndex, e)}
                  />
                </td>
              ))}
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
};

export default Sheet;

This works, but this is always for a 3x3 matrix. I have to set this dynamic, so I thought I'll set the default state with ES6 array construction like:

const n = 4; // Will be set through props
const [matrix, setMatrix] = useState(Array(n).fill(Array(n).fill(null)));

But when I use this case and I update (type a number in an input field), the whole column in the matrix will get that number.

Can anybody explain this?

When I use this piece of code:

const [matrix, setMatrix] = useState(
    Array.from({ length: 3 }, v => Array.from({ length: 3 }, v => null))
  );

it works again.

Share Improve this question edited Dec 9, 2019 at 13:22 jonrsharpe 122k30 gold badges267 silver badges474 bronze badges asked Dec 9, 2019 at 13:19 Ronald Groot JebbinkRonald Groot Jebbink 1452 gold badges2 silver badges9 bronze badges 4
  • Array(n).fill(null) is only evaluated once, and the value is used to fill the outer array. – jonrsharpe Commented Dec 9, 2019 at 13:21
  • So the arrays in the outer array are actually the same arrays? – Ronald Groot Jebbink Commented Dec 9, 2019 at 13:35
  • Yes, multiple references to the same array, which is why changing one changes "all of them". – jonrsharpe Commented Dec 9, 2019 at 13:37
  • Good to know and to keep in mind! – Ronald Groot Jebbink Commented Dec 9, 2019 at 13:39
Add a ment  | 

1 Answer 1

Reset to default 9

Array(n).fill(null) is evaluated once and it populates the entire array with the same reference values and hence when you update a single column, all rows are updated.

To solve this issue, you can use Array.from to create a 2D matrix like Array.from({length: n},()=> Array.from({length: n}, () => null))

const { useState } = React;

const n = 4;
const Sheet = () => {
  const [matrix, setMatrix] = useState(Array.from({length: n},()=> Array.from({length: n}, () => null)));

  const handleChange = (row, column, event) => {
    let copy = [...matrix];
    copy[row][column] = +event.target.value;
    setMatrix(copy);

    console.log(matrix);
  };

  return (
    <div className="sheet">
      <table>
        <tbody>
          {matrix.map((row, rowIndex) => (
            <tr key={rowIndex}>
              {row.map((column, columnIndex) => (
                <td key={columnIndex}>
                  <input
                    type="number"
                    onChange={e => handleChange(rowIndex, columnIndex, e)}
                  />
                </td>
              ))}
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
};

ReactDOM.render(<Sheet />, document.getElementById('app'));
<script src="https://cdnjs.cloudflare./ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare./ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="app" />

本文标签: javascriptUpdate a 2D array matrix with useState in ReactStack Overflow