BeHFaR
BeHFaR

Reputation: 129

React: Passed states to child components don't get updated when they change within the parent

I have read similar questions, but still can't explain why the passed state to child components, which is defined as a separate state in there (for event controlling reasons), doesn't get updated and therefore renders the children, while it got updated in the parent.

Please check this CodeSandbox or the below snippet to see the problem. (The parent state changes on inputs' onChange event in child components, but it doesn't re-render the children with the updated value).

const {useState} = React;

const App = () => {
  const [array, setArray] = useState([1, 2, 3, 4, 5]);
  const changeHandler = (newID, index) => {
    setArray([...array.slice(0, index), newID, ...array.slice(index + 1)]);
  };
  return (
    <div className="App">
      <h1>Array in parent:</h1>
      {array.map((el) => el)}
      <h1>Array in children</h1>
      {array.map((el, index) => (
        <InputComponent
          key={index}
          passedId={el}
          index={index}
          changeHandler={changeHandler}
        />
      ))}
    </div>
  );
}

const InputComponent = ({ passedId, index, changeHandler }) => {
  const [person, setPerson] = useState({
    id: passedId
  });
  return (
    <input
      type="number"
      min="1"
      max="10"
      value={person.id}
      onChange={(e) => changeHandler(e.target.value, index)}
    />
  );
};


ReactDOM.createRoot(
    document.getElementById("root")
).render(
    <App />
);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.development.js"></script>

Thanks.

Upvotes: 0

Views: 73

Answers (1)

Ivana Murray
Ivana Murray

Reputation: 338

In your InputComponent you set the value using internal state. You assign it once and that's it. Once it's assigned it's original value it doesn't keep listening to changes in the passed down state.

const InputComponent = ({ passedId, index, changeHandler }) => {
  const [person, setPerson] = useState({
    id: passedId
  });
  return (
    <input
      type="number"
      min="1"
      max="10"
      value={passedId}
      onChange={(e) => changeHandler(e.target.value, index)}
    />
  );
};

Or you can useEffect to listen to changes

const InputComponent = ({ passedId, index, changeHandler }) => {
  const [person, setPerson] = useState({
    id: passedId
  });
  useEffect(() => {
    setPerson({id: passedId})
  }, [passedId])
  return (
    <input
      type="number"
      min="1"
      max="10"
      value={person.id}
      onChange={(e) => changeHandler(e.target.value, index)}
    />
  );
};

Upvotes: 2

Related Questions