1
votes

I have an select input with 3 options and 3 text inputs. The ideia is: I select the desired property (for example: A) and only this input will be abled for the user, the other ones will be disabled.

Then I click on the "Calculate" button bellow the disabled inputs, and the calculated value for that input appears, based on the property I inserted (in this case, just to simplify, this value is always 123).

import React, { useState } from "react";
import "./styles.css";

export default function App() {
  const [models, setModels] = useState([
    { name: "A", value: undefined },
    { name: "B", value: undefined },
    { name: "C", value: undefined }
  ]);

  const onModelChange = (e) => {
    const { name, value } = e.target;
    let newModels = models;
    newModels[
      newModels.findIndex((model) => model.name === name)
    ].value = parseInt(value, 10);
    setModels(newModels);
  };

  const onCalculate = (modelName) => {
    let newModels = models;
    newModels[
      newModels.findIndex((model) => model.name === modelName)
    ].value = 123;
    console.log(newModels);
    setModels(newModels);
  };

  const [selectedOption, setSelectedOption] = useState("A");

  const handleChange = (e) => {
    setSelectedOption(e.target.value);
  };

  return (
    <div className="App">
      <select onChange={handleChange} value={selectedOption}>
        <option value="A">A</option>
        <option value="B">B</option>
        <option value="C">C</option>
      </select>
      <br />
      {models.map((model) => (
        <div key={model.name}>
          <input
            placeholder={model.name}
            name={model.name}
            label={model.name}
            width="100px"
            type="number"
            min="0"
            max="1000"
            value={model.value}
            onChange={onModelChange}
            disabled={selectedOption !== model.name}
          />
          <br />
          <button
            name="refresh"
            width="24px"
            height="24px"
            onClick={() => onCalculate(model.name)}
            disabled={selectedOption === model.name}
          >
            Calculate
          </button>
          <br />
        </div>
      ))}
    </div>
  );
}

My problem is that the values in the inputs come from a state variable, named "models", and after I click on Calculate, this variable is changed, as you can see on the console, but the value is not showing in the disabled inputs.

Does anyone know how to fix this?

Link to codesandbox: https://codesandbox.io/s/affectionate-ives-uytgy?file=/src/App.js

1
You are mutating state. Don't mutate state - setModels([...newModels])Adam
you're right, thank you so much!!Amanda

1 Answers

1
votes

PROBLEM

You're mutating the state array and updating it. React has no idea whether the state has changed or not, since you're passing the old reference to the setState.

SOLUTION

  1. First, get the copy the state array.
  2. Mutate the copied version of the state array.
  3. Update your state with a new updated mutated array.
 const onModelChange = e => {
    const { name, value } = e.target;
    let newModels = [...models];
    newModels[
      newModels.findIndex(model => model.name === name)
    ].value = parseInt(value, 10);
    setModels(newModels);
  };

  const onCalculate = modelName => {
    let newModels = [...models];
    newModels[
      newModels.findIndex(model => model.name === modelName)
    ].value = 123;
    setModels(newModels);
  };

You could check similar problem in this example :- https://stackblitz.com/edit/react-osxmnr