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.