Refine Form-Field communication
kettanaito opened this issue · 2 comments
kettanaito commented
What
I suggest to refine the existing Form-Field communication.
Why
Current implementation relies on dispatching side-effects during Field's componentWillReceiveProps
, which is not recommended. This, eventually, results into unstable tests.
How
- Consider RxJs patterns
Roadmap
- Buffer
fieldUnregister
event unregister multiple fields within a single state update - Buffer
fieldChange
event to handle concurrent field changes as a single state update - Consider new React Context API to propagate context to fields (#232)
- Refine and minimize the data passed via context
- Handle controlled fields interactions
- Handle uncontrolled fields interactions
kettanaito commented
Render from context instead of an internal variable
// createField.js
constructor() {
this.initialFieldState = this.register()
}
// create a shorthand that always resolves to
// a) relevant field state reference in the form's state
// b) initial field state, in case form state is not yet updated
get fieldState = () => {
return R.pathOr(this.fieldPath, this.initialFieldState, this.context.fields)
}
render() {
// reference field state consistently, it's derived from the context
const { fieldState } = this
const fieldProps = deriveFrom(fieldState)
return (...)
}
Communicate field component update
// createField.js
componentDidUpdate(nextProps) {
// always emit field update event, no other logic here
this.eventEmitter.emit('fieldDidUpdate', { prevProps: this.props, nextProps })
}
// Form.jsx
constructor() {
fromEvent(this.eventEmitter, 'fieldDidUpdate').subscribe(this.fieldDidUpdate)
}
// listen to any field update and decide upon the necessity of the state update
// @todo propagate the "fieldState" reference to know which field has updated
fieldDidUpdate = ({ prevProps, nextProps, fieldState }) => {
const { valuePropName } = fieldState
// this should fallback to "false" when the field update is caused by fields state update
// which cause "context" update, and field re-render, that triggers "cDU".
if (!R.equals(prevProps[valuePropName], nextProps[valuePropName]) {
this.updateFieldsWith(nextFieldState)
}
}
kettanaito commented
The areas covered by the chunked state updates:
- change
- focus
- blur
- reset
- clear
- setValues
- setErrors
- serialize