Home > Blockchain >  How to overwrite internal component state from the outside
How to overwrite internal component state from the outside

Time:12-15

I have a rather simple NumberInput component/control which handles its internal state (its current value) with useState. The "outside world" is not interested in this state but only receives updates via the callback function onSubmit which is called on enter & blur.

I also have a component called MinMaxNumberInputs which is built of 2 NumberInputs. Those 2 NumberInputs don't know anything from each other and the parent MinMaxNumberInputs has to deal with some "value syncing" by e.g. ensuring that min <= max etc.

This last part is where I'm a little stuck, as I don't know how to "force set" or override the internal state of the NumberInputs from MinMaxNumberInputs when needed.

Probably best explained via code:

NumberInput.tsx

// ...

type NumberInputProps = {
  value: number;
  onSubmit: (value: number) => void;
};

export default function NumberInput(props: NumberInputProps) {
  // [1] props.value is obviously only applied on creation.
  //     Future changes have no effect.
  const [value, setValue] = useState(props.value);

  // Called on enter & blur
  const submitValue = () => props.onSubmit(value);

  // ...

  return <input value={value} {/* ... */} />;
}

MinMaxNumberInputs.tsx

// ...

export const MinMaxValueInput = () => {
  // Only for simpler showcasing, using global redux state in real world...
  const [minValue, setMinValue] = useState(0);
  const [maxValue, setMaxValue] = useState(0);

  const onMinValueChanged = (newMinValue: number) => {
    // [2] Ensure that entered value (min here) stays the same but adjust max if required
    //     ??? How to set adjusted value in max NumberInput ???
    const newMaxValue = Math.max(newMinValue, maxValue);
    setMinValue(newMinValue);
    setMaxValue(newMaxValue);
  };

  const onMaxValueChanged = (newMaxValue: number) => {
    // [3] Ensure that entered value (max here) stays the same but adjust min if required
    //     ??? How to set adjusted value in min NumberInput ???
    const newMinValue = Math.min(minValue, newMaxValue);
    setMinValue(newMinValue);
    setMaxValue(newMaxValue);
  };

  // ...

  return (
    <>
      <NumberInput value={minValue} onSubmit={onMinValueChanged} />
      <NumberInput value={maxValue} onSubmit={onMaxValueChanged} />
    </>
  );
};

The thing is:

When newMaxValue is adjusted in [2] (or newMinValue in [3]), MinMaxNumberInputs is holding the correct adjusted values in its state but those values are not propagated to the according NumberInput and the shown values are therefore not updated/corrected.

I fully understand why this is not working. The value property is only applied once to the NumberInputs internal state at [1] but not anymore afterwards. However, I have no idea on how to overcome this without "breaking the boundaries" of the NumberInput (e.g. using some global state there as well, ...).

I'd really appreciate some guidance on this!

Thanks

CodePudding user response:

Your NumberInput is UNCONTROLLED component, your interface is misleading, it should be named initialValue instead of value.

Therefore what you want is whats called a "hybrid component", in this case when you DO pass value prop, it becomes CONTROLLED:

export default function NumberInput(props: NumberInputProps) {
  const [value, setValue] = useState(props.initialValue);
  
  useEffect(() => {
    setValue(props.value)
  }, [props.value])

  return <input value={value}  />;
}
  • Related