Reputation: 129
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
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