El siguiente código tiene un botón para agregar entradas y otro botón para agregar todos los valores en las entradas, suponiendo que sean números. La última línea es para mostrar la suma de todo. Sin embargo, por alguna razón, solo obtiene el valor de la última entrada. Tampoco se reinicia. Pensé que tener setGrade (0) haría esto, pero sigue agregando el último número sin reiniciar.
Me gustaría saber por qué este es el caso con el siguiente código. La identificación de los campos de entrada es solo el número a partir de 1.
function Start(){ const [rows, setRows] = useState([]); const [inputNum,setNum] = useState(1); const [totalGrade, setGrade] = useState(0); const addInput = () =>{ setNum(inputNum+1); setRows(rows.concat(<Inputs key={rows.length} label={inputNum.toString()}></Inputs>)); } const addGrade = () =>{ setGrade(0); for(let i =0;i<rows.length;i++){ setGrade(parseInt(document.getElementById((i+1).toString()).value,10) +totalGrade) } } return( <div> <h1>Calculate your GPA!</h1> {rows} <button class="button2"onClick={addInput}>Add Input</button> <button class="button2"onClick={addGrade}>Compute Grade</button> <h2>Grade: {totalGrade}</h2> </div> ); }
No debería mezclar métodos de elementos nativos como getElementById
en el código React.
Agregue un onChange
directamente en los elementos de entrada.
Cree un nuevo estado (un objeto) que mantenga un registro de cada cambio en una entrada (identificado por clave/id) donde el valor es el nuevo valor de la entrada.
No establezca el estado en un bucle, es una mala práctica.
Así es como lo abordé (tuve que simplificar el ejemplo ya que no tengo acceso al componente Inputs
).
const { useEffect, useState } = React; function Example() { const [inputNum, setInputNum] = useState(0); // The new state which maintains all the input values const [inputData, setInputData] = useState({}); const [totalGrade, setTotalGrade] = useState(0); // `addInput` is now only responsible // for updating the number of rows function addInput() { setInputNum(inputNum + 1); } // NEW FUNCTION: it handles the update of the // `inputData` state. It grabs the id and value from // the input, and then updates the state with that // new information function handleChange(e) { const { id, value } = e.target; // Take the previous state (object), and update it // by spreading (copying) out the previous object, // and adding a new property with the id as key // and the value as the value. setInputData(prev => ({ ...prev, [id]: value })); } // `sumGrade` - I renamed this - grabs the Object.values // of the inputData state and then creates a sum of all // of those values using `reduce`. It then, finally, sets // the `totalGrade` state. function sumGrade() { const values = Object.values(inputData); const result = values.reduce((acc, c) => { return acc + +c; }, 0); setTotalGrade(result); } // NEW FUNCTION: this builds an array of new inputs // which can be used in the JSX function buildRows() { const arr = []; for (let i = 0; i < inputNum; i++) { arr.push(<input onChange={handleChange} type="number" key={i} id={i} value={inputData[i]}/>); } return arr; } return ( <div> <h1>Calculate your GPA!</h1> {buildRows()} <button class="button2"onClick={addInput}>Add Input</button> <button class="button2"onClick={sumGrade}>Compute Grade</button> <h2>Grade: {totalGrade}</h2> </div> ); } // Render it ReactDOM.render( <Example />, document.getElementById("react") );
input { display: block; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script> <div id="react"></div>