kettanaito / react-advanced-form

Functional reactive forms. Multi-layer validation, custom styling, field grouping, reactive props, and much more.

Home Page:https://redd.gitbook.io/react-advanced-form

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Refine Form-Field communication

kettanaito opened this issue · comments

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

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)
  }
}

The areas covered by the chunked state updates:

  • change
  • focus
  • blur
  • reset
  • clear
  • setValues
  • setErrors
  • serialize