0

I'm attempting to create a page using React, whereby I can update a single element of the state; here is how the state is defined:

interface MyState {
    data?: MyData;
    loading: boolean;
}

interface MyData {
    id: number;
    description: string;
    test: string;    
}

I have the following inside my render function:

return <div>
    <h1>Description: {myData.description}</h1>
    <br/><br/>
    <input type="text" value={emailType!.test} onChange={this.handleChange} />

</div>;

And the handleChange (which is the heart of my issue):

handleChange(event: React.FormEvent<HTMLInputElement>) {        
    this.setState({ emailType!.test: event.currentTarget.value });
}

As I'm using tsx, the function above won't even compile. However, it does illustrate what I'm trying to do. Typically, when I've called this.setState, I've done so with a full state (that is, I know the entire new state). In this case, I only want to change the contents of a single field: is that possible?

Paul Michaels
  • 16,185
  • 43
  • 146
  • 269
  • 1
    Yes, setState is designed to only update what you need, it's actually uncommon to update everything in state. Don't you just love how TS costs you so much time doing basic things? ;) – Dominic Mar 29 '18 at 08:37
  • Not related to the issue but isn't it safer to enclose JSX between `()` ? like `return ()` – 3Dos Mar 29 '18 at 08:40
  • @DominicTobias - I'm certainly no expert with TS, but surely the things that it forces you to do, JS also forces you to do... it's just that TS catches them at compile time? – Paul Michaels Mar 29 '18 at 09:25
  • @3Dos - why is that safer? – Paul Michaels Mar 29 '18 at 09:27
  • In practice with TS you spend a lot of time just getting the thing to compile even if you know what you're doing. TS can't find definition for dynamic imports, TS fails because it requires a field and doesn't realise you're spreading it in, TS ... you get the idea, you spend hours Googling how to get things running you know work perfectly well. Also PropTypes check props are runtime in dev mode, that's a pretty powerful feature to defend against API changes that static compilers can't do – Dominic Mar 29 '18 at 09:32
  • @DominicTobias but if you got this knowledge once, it's will be faster in the future, it's like "memoization" – uladzimir Mar 29 '18 at 11:24

1 Answers1

0

setState allows changing only top-level key in the state like

handleChange = (event: React.FormEvent<HTMLInputElement>) => {
    const emailType = { ...emailType, test: event.currentTarget.value }
    this.setState({ emailType })
}

Don't forget to bind your function to the proper context.

Another option is to use function as a parameter in setState:

this.setState((oldState) => {
  return {
    ...oldState,
    emailType: {
      ...oldState.emailType,
      test: event.currentTarget.value
    }
  }
})
uladzimir
  • 5,639
  • 6
  • 31
  • 50