Closed nighca closed 2 years ago
Some other concerns:
In our practices in Qiniu, it is a common mistake to misuse value
& _value
- although the differences are documented here.
bindInput
bindInput
is important for avoid misuse of value
& _value
, but it is not natural for beginners.
Debounce is unnecessary for most inputs (which will not change frequently).
The proposal includes two parts:
FieldState
DebouncedState
& DebouncedFieldState
for certain situationsCertain situations includes:
class DebouncedState
wraps another state, and reflect its change, while with a certain delay.
class DebouncedFieldState
is a simple shortcut for DebouncedState
+ FieldState
, which acts like a FieldState
while with a certain delay (which is almost the same as legacy FieldState
).
class DebouncedState<V> implements IState<V> {
constructor(public $: IState<V>, delay = 200) {
// ...
}
// ...
}
class DebouncedFieldState<V> extends DebouncedState implements IState<V> {
constructor(public initialValue: V, delay = 200) {
super(new FieldState(initialValue), delay)
}
}
DebouncedFieldState
State initialization:
const nameField = new DebouncedFieldState('foo').validators(...)
State binding:
const nameFieldForBinding = nameField.$
// HTML `input`
<input value={nameFieldForBinding.value} onChange={e => nameFieldForBinding.onChange(e.target.value)} />
// react-icecream `TextInput`
<TextInput value={nameFieldForBinding.value} onChange={nameFieldForBinding.onChange} />
// react-icecream `form-x/TextInput`
<TextInput state={nameFieldForBinding} />
State operation:
const formState = new FormState({
name: nameField
})
const value = formState.value
value.name // 'foo'
formState.set({ name: 'bar' }) // or: nameField.set('bar')
value.name // bar
DebouncedState
With DebouncedState
, you can add debounce to any kind of state in addition to FieldState
:
const fullNameState = new FormState({
first: new FieldState('foo'),
last: new FieldState('bar')
})
const debouncedFullNameState = new DebouncedState(fullNameState)
// For details of ProxyState, see https://github.com/qiniu/formstate-x/issues/49
const fullNameTextState = new ProxyState(
fullNameState,
({ first, last }) => `${first} ${last}`,
fullName => {
const [first, last] = fullName.split(' ')
return { first, last }
}
)
const debouncedFullNameTextState = new DebouncedState(fullNameTextState)
Based on certain situations explained above.
Use DebouncedFieldState
instead of FieldState
when the field state is intended to be bound to a text input (like HTML input type="text"
, HTML textarea
, react-icecream TextInput
, ...)
Use DebouncedState
when you want to add certain delay between the value change & value consumption — value consumption may be expensive, while other tools like React useDeferredValue
& startTransition
are not proper for the situation.
With
useDeferredValue
(andstartTransition
) in React 18, the debounce between (FieldState
's)value
&_value
may be unnecessary.Current behavior:
https://github.com/qiniu/formstate-x/blob/bd4ec5e16194949a224fc7b183e5ea59224351ea/src/fieldState.ts#L30-L34