Skip to main content

Differences from Final Form

The project has a number of differences in working with the Final Form.

Not only form

In the Final Form you can do most things using form.

effector-final-form provides several entities:

const { $, api } = createForm<{ firstName: string }>({
onSubmit: onSubmitMock,
subscribeOn: ['initialValues', 'values'],
});

form.$ no undefined values

Values of some FormState properties are forcibly replaced by null to avoid a situation where the derived from form.$ may contain undefined.

List of values:

  • active
  • errors
  • modified
  • submitErrors
  • touched
  • visited

field.$ no undefined values

Values of some FieldState properties are forcibly replaced by null to avoid a situation when yours derived $ from field.$ may contain undefined.

api.revalidateFx

Not presented in Final Form.

Triggers form revalidation. Can be useful when the form validation function depends on dynamic parameters (e.g. store value)

const setError = createEvent<string>();
const $error = createStore<string>('');

sample({ clock: setError, target: $error });
sample({ clock: setError, target: api.reValidateFx });

const validationFx = attach(() => {
effect: ({ fields, error }) => {
if (fields.firstName.length <= 2) {
return { firstName: error }
}
},
source: $error,
mapParams: (fields, error) => ({ fields, error })
})

setError('Incorrect value');

field.api.setValidationFn

Not presented in Final Form.

Allows you to dynamically set validation function. Uses effect.use under the hood.

api.setSubmitFn

Not presented in Final Form.

Allows you to dynamically set submit function. Uses effect.use under the hood.

createForm.initialValues

You can not pass undefined initial values in createForm. But it is possible to provide them on api.registerField.

const form = createForm<{ name: string }>({
onSubmit: () => {},
});

form.api.registerField({
name: 'name',
initialValue: 'John',
...
})

form & field subscriptions

To subscribe to changes in a form or field, you should pass the subscribeOn parameter.

Values not included in subscribeOn will be specified in the subscription with the value false.

Except values of fields.

In the effector-final-form you can not create many subscribers with different subscriptions.

const { api } = createForm<{ firstName: string }>({
onSubmit: onSubmitMock,
subscribeOn: ['initialValues', 'values'],
});

api.registerField({
name: 'firstName',
subscribeOn: ['active'],
});

form.isValidationPaused()

It is a way to find out if validation currently paused.

// Final Form
form.isValidationPaused(); // boolean

// effector-final-form
form.$.map((s) => s.isValidationPaused); // Store<boolean>

form.registerField()

In the Final Form it is a way to register a new field and subscribes to changes to it. In the effector-final-form you can not set a subscriber.

// Final Form
form.registerField('firstName', () => {}, { active: true }, config: { initialValue: 'John' });

// effector-final-form
api.registerField({name: 'firstName', subscribeOn: ['active'], initialValue: 'John' })

form.getState()

You don't need this method!

getState() gives rise to difficult to debug imperative code and kind of race condition. Prefer declarative sample to pass data from store and attach for effects

It is a way to get the current state of the form without subscribing.

// Final Form
const formState = form.getState();

// effector-final-form
const formState = form.$.getState();

form.getFieldState()

It is a way to get the state of a specific field.

// Final Form
const firstNameState = form.getFieldState('firstName');

// effector-final-form
const $firstName = $fields.map((fields) => fields.firstName);

form.subscribe()

It is a way to ubscribes to changes to the form.

In the effector-final-form you can not create many subscribers with different subscriptions.

const subscriber = () => {};

// Final Form
form.subscribe(subscriber, { active: true });

// effector-final-form
sample({ clock: form.$, target });