What would happen if a react hook's state is updated directly instead of calling the set updater function.
const MyComponent = () => {
const [formData, setFormData] = useState({
gender: "",
dob: "",
contact: "",
institute: "",
institute_other: "",
occupation: "",
occupation_other: "",
street_address: "",
city: "",
division: "",
country: "",
email: "",
user_name: "",
});
const [username, setUserName] = useState("");
const [email, setEmail] = useState("");
}
This is the hook that I have initialized
In an input handler function I am updating a certain element in the state variable object directly like this --
// ... My other codes
formData.division = "some_Division";
formData.city = "some_city";
// ... Rest of the code
This happens to update my state object. But I definitely understand that this is not a good practice, but can I get a clarification about how it breaks the rule of hooks in react and what problems it might pose in the future (if it may).
N.B: I have tried to update the state in this way inside the input handler function but with no luck!
const handleInputChange = (e) => {
switch (e.currentTarget.name) {
case "country":
setUpdateDivision(true);
setUpdateCity(true);
setDivisionHook("");
setCityHook("");
setFormData((formData) => ({ ...formData, division: "", city: "" }));
setDivisionOptions([]);
setCityOptions([]);
console.log(e.currentTarget.selected);
break;
case "division":
setUpdateCity(true);
setCityHook("");
setFormData((formData) => ({ ...formData, city: "" }));
setCityOptions([]);
break;
case "institute":
setUpdateInstitute(true);
break;
case "occupation":
setUpdateOccupation(true);
break;
default:
break;
}
setFormData({
...formData,
[e.currentTarget.name]: e.currentTarget.value,
email: email,
user_name: username,
});
};
It does not update the state variable.
Edit: I have added the complete handleInputChange function for clarity.
CodePudding user response:
The issue with updating the state directly is that is a mutation and won't trigger React to rerender a component with the updated state value. It's not breaking the "Rules of Hooks", it's breaking React's rule against state/props mutations.
Do Not Modify State Directly
For example, this will not re-render a component:
// Wrong state.comment = 'Hello'; Instead, use setState(): // Correct setState({comment: 'Hello'});
I suspect your enqueued state updates aren't working due to a stale enclosure. Using a functional state update resolves this by updating from the previous state versus the state closed over in scope. This also helps if you are enqueueing several state updates within the same enclosure where each update needs to update from the previous result.
setFormData(formData => ({
...formData, // shallow copy previous state
[e.currentTarget.name]: e.currentTarget.value, // update property
}));
Update
Another issue is that enqueued React state updates are not immediate. They are enqueued (think of this as a request to React to "please update state X with value Y at your earliest convenience"), and batch processed asynchronously. When you update with setFormData
several times and don't use a functional update then each update overwrites the previously enqueued update when it's processed using the current state value of the enclosure over what is passed in the updater function.