Home > Back-end >  input onChange is wiping all elements from DOM in React. The input form works well with a button, bu
input onChange is wiping all elements from DOM in React. The input form works well with a button, bu

Time:03-06

So I'm creating a grid that you can resize using two input fields on the app. I have the input for cells across, input for cells down and the button to set the grid which works nicely. I want to change so that the input updates the state stored on cellsAcross and cellsDown. When I remove the button and add the onChange attribute to the input elements, it works if I don't refresh the browser, but as soon as everything renders for the first time, when adding an input everything in the DOM disappears.

Here's the code with the button:

function App() {
  const [cellsAcross, setCellsAcross] = useState(5);
  const [cellsDown, setCellsDown] = useState(5);

  const getGridSize = () => {
    const inputAcross = document.getElementById("cells-across").value;
    const cellsAcross = parseInt(inputAcross);
    setCellsAcross(cellsAcross);
    const inputDown = document.getElementById("cells-down").value;
    const cellsDown = parseInt(inputDown);
    setCellsDown(cellsDown);
    console.log(`Across: ${cellsAcross} | Down: ${cellsDown}`);
  };

  

  return (
    <div className="app">
      <Header />
      <CellGrid numberOfColumns={cellsAcross} numberOfRows={cellsDown} />
      <label htmlFor="cells-across">Across</label>
      <input 
        type="number" 
        id="cells-across" 
        name="cells-across" 
        min="1"
      />
      <br />
      <label htmlFor="boxes-down">Down (1-20):</label>
      <input 
        type="number" 
        id="cells-down" 
        name="cells-down" 
        min="1"
      />
      <br />
      <button onClick={getGridSize}>Make Grid</button>
      <br />
    </div>
  );
}

export default App;

And this is what I want it to be:

import React, { useState } from "react";
import CellGrid from "./CellGrid";
import "./App.css";
import Header from "./Header";

function App() {
  const [cellsAcross, setCellsAcross] = useState(5);
  const [cellsDown, setCellsDown] = useState(5);

  const getGridSize = () => {
    const inputAcross = document.getElementById("cells-across").value;
    const cellsAcross = parseInt(inputAcross);
    setCellsAcross(cellsAcross);
    const inputDown = document.getElementById("cells-down").value;
    const cellsDown = parseInt(inputDown);
    setCellsDown(cellsDown);
    console.log(`Across: ${cellsAcross} | Down: ${cellsDown}`);
  };

  return (
    <div className="app">
      <Header />
      <CellGrid numberOfColumns={cellsAcross} numberOfRows={cellsDown} />
      <label htmlFor="cells-across">Across</label>
      <input
        type="number"
        id="cells-across"
        name="cells-across"
        min="1"
        onChange={getGridSize}
      />
      <br />
      <label htmlFor="boxes-down">Down (1-20):</label>
      <input
        type="number"
        id="cells-down"
        name="cells-down"
        min="1"
        onChange={getGridSize}
      />
      
    </div>
  );
}

export default App;

CodePudding user response:

Update onChange={()=>{setCellsAcross(e.target.valeu)}} to just set the state value to the new value. That will cause the entire component to re-render.

Related - it's bad practice to pull values out of the DOM directly. If you really wanted to do get the value of that input elsewhere in code, you'd add a const myCellsAcrossRef=useRef()and then add a ref attribute to the element:ref={myCellsAcrossRef}`.

Finally, you don't need your getGridSize() method if you just set the across & down values onChange, but if you did ... you'd name it "setGridSize() or updateGridSize()" to indicate the method changes things. "Get" implies the function will not have side effects/mutations.

  • Related