skip to Main Content

I’m trying to do a conditional state update in react where some keys are only updated if another value changes (used to reset some values for settings to null if certain modes are selected). This pattern used to work fine (like years ago), but now it seems like React’s setState expects a Pick object instead of Partial, which works great if inlining your state object into the setState call, but prevents conditional construction of the state object to update.

Attempted code below, fails due to setState not taking a partial. newValue is a numeric parameter to the change handler function that this code excerpt is from.

const newState: Partial<localState> = {};
if (newValue !== 2) {
    newState.settingA = null;
    newState.settingTwo = null;
}
newState.multiCurrencyDynamicMode = newValue;
this.setState(newState);

I tried switching newState to const newState: Pick<localState, keyof localState> but this fails due to this definition of pick expecting every key of localState to be present.

2

Answers


  1. The definition for Partial is:

    /**
     * Make all properties in T optional
     */
    type Partial<T> = {
        [P in keyof T]?: T[P];
    };
    

    So, without seeing how localstate is defined in your code, I’m guessing that it doesn’t allow undefined properties; but by using Partial, it’s effectively creating this as the type:

    // Partial means that every property on your type now allow `undefined`:
    type localState = {
      settingA?: string | null;
      settingTwo?: string | null;
      otherProperty?: int;
      // etc...
    }
    

    Which is probably incompatible with your version of localstate. So, there’s two fixes you can choose:

    1. Change every property on localstate to optional – probably not what you want to do!
    2. Use Pick and just list the keys you want to change, eg:
    const newState: Pick<localState, 'settingA' | 'settingTwo'> = {
      settingA: localState.settingA,
      settingTwo: localState.settingTwo,
    };
    
    if (newValue !== 2) {
        newState.settingA = null;
        newState.settingTwo = null;
    }
    newState.multiCurrencyDynamicMode = newValue;
    this.setState(newState);
    
    Login or Signup to reply.
  2. In a class component with TypeScript, when you’re conditionally updating the state, you can indeed run into typing issues with TypeScript if your setState call doesn’t align with the expected type of your state.

    Here’s a pattern you can follow to ensure that TypeScript knows you’re providing a valid partial state update:

    // Assuming localState is the type of your component's state
    interface localState {
      settingA: string | null;
      settingTwo: string | null;
      multiCurrencyDynamicMode: number;
      // ... other state keys
    }
    
    class YourComponent extends React.Component<{}, localState> {
      // ...
    
      handleChange = (newValue: number) => {
        // Start by defining an update object that includes the keys you want to update.
        let update: Partial<localState> = { multiCurrencyDynamicMode: newValue };
    
        if (newValue !== 2) {
          // When a condition is met, extend the update object with additional keys.
          update = {
            ...update,
            settingA: null,
            settingTwo: null,
          };
        }
    
        // Now, TypeScript knows that `update` is a Partial of localState
        this.setState(update);
      }
    
      // ...
    }
    

    In this example, you start with an update object that has the mandatory update for multiCurrencyDynamicMode. Then, based on your condition, you extend that update object with the additional keys (settingA and settingTwo). Finally, you call this.setState with the update object.

    Since this.setState in React accepts a partial state update, this pattern should work correctly, and TypeScript should not complain as long as the keys in the update object are valid keys from your state type (localState in this case). This is because TypeScript understands that Partial<localState> is a type that can contain any subset of the properties of localState.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search