0

I have two functions that duplicate code except for the name of the key in the call to setState():

fooFunc(value: Moment) {
  if (condition){
   this.setState({foo: value});
  } else {
   doSomethingElse();
   this.setState({foo: undefined});
  }
}

barFunc(value: Moment) {
  if (condition){
   this.setState({bar: value});
  } else {
   doSomethingElse();
   this.setState({bar: undefined});
  }
}

How can I refactor this to a single method that accepts the name of the key as a parameter and sets the state accordingly?

// something like this, but this doesn't work:
parameterizedFunc(name: string, value: Moment){
  if (condition){
    this.setState({[name]:value});
  } else {
    this.setState({[name]:undefined});
  }
}

When using the above technique, I am getting the following (redacted) error message:

"Argument of type '{ [x: string]: moment.Moment; }' is not assignable to parameter of type 'MyState | Pick<MyState, keyof MyState> | ((prevState: Readonly<...>, props: Readonly<...>) => MyState | ... 1 more ... | null) | null'.\n Type '{ [x: string]: Moment; }' is missing the following properties from type 'Pick<MyState, keyof MyState>': aList, bList, cList, dList, and 8 more."

Scott Baker
  • 10,013
  • 17
  • 56
  • 102
  • That's a typescript error that is related to type of the state. You should include all the relevant code to reproduce the error. Please read [mre]. – super Nov 29 '22 at 14:36
  • Does this answer your question? [React set state property dynamically](https://stackoverflow.com/questions/37591430/react-set-state-property-dynamically) – D Lav Nov 29 '22 at 15:33

1 Answers1

1

I found that I need to use the "previous state" overload of setState, and use it to populate the "missing" properties:

parameterizedFunc(name: string, value: Moment){
  if (condition){
    this.setState(prevState => {...prevState, [name]:value});
  } else {
    this.setState(prevState => {...prevState, [name]:undefined});
  }
}
Scott Baker
  • 10,013
  • 17
  • 56
  • 102
  • type of name should be 'keyof MyState'. This may fix it without need of passing a callback to setState, since you are using class component it does that state spreading automatically – Oktay Yuzcan Nov 29 '22 at 16:03