0

I'm trying to update state object in a functional component through TextInput fields without changing the other entry.

const [state, setState] = React.useState({
  foo: 'bar',
  baz: 'qux',
});

The TextInputs:

<TextInput
  id="foo"
  value={state.foo}
  onChangeText={(text) => updateState('foo', text)}
/>
<TextInput
  id="baz"
  value={state.baz}
  onChangeText={(text) => updateState('foo', text)}
/>

The (non-working) function to update the state since state hooks don't allow merging states:

const updateState = (key, value) => {
  var newState = state;
  newState[key] = value;
  setState(newState);
};

Here's a prepared snack to play with the code and see it in action.

If you log the state to the console via the button you can see that the state actually updates in the background, albeit just with a single character unless you paste something into the input field. If I run this on Android I can actually see the character(s) for a short moment before the text in the TextInput gets reset.

I suspect this has to do with asynchronous calls? I also tried this answer that uses onChange instead of onChangeText but was unable to get it to work.

Fivefold
  • 3
  • 2

1 Answers1

0

Update the state by spreading the original value of the state to an object, and override the with [key]: value (snack):

const updateState = (key, value) => {
  setState(oldState => ({
    ...oldState,
    [key]: value,
  }));
};
Ori Drori
  • 183,571
  • 29
  • 224
  • 209
  • I understand this works, but **why** does it work compared to the variant with the temporary copy? – Fivefold Mar 24 '21 at 14:13
  • Because you are mutating the old state instead of cloning it, react thinks that it's the old state, and doesn't re-render the component. – Ori Drori Mar 24 '21 at 14:27