Watch out for shallow merge

This is part of the Semicolon&Sons Code Diary - consisting of lessons learned on the job. You're in the dumb-mistakes-and-gotchas category.

Last Updated: 2024-04-24

I had this function and the following two calls:

const handleFormInput = (stateUpdate) => {
  setFormData((prevState) => ({
    ...prevState,
    ...stateUpdate,
  }));
};

onChangeText={(text) => handleFormInput({ user: { email: text } })}
onChangeText={(text) => handleFormInput({ user: { password: text } })}

The result was that the user key just had {password: 'x'} - i.e. the {email: ''} content from the previous call to handleFormInput disappeared. Not what I wanted at all.

Why did this happen? Because the merging was "shallow", in the sense that it replaced the entire top-level user key (including its email sub-key). Certain "deep merge" algorithms avoid this.

Lesson

Watch out when merging deeply nested objects that you don't wipe nested data.