
Research
/Security News
9 Malicious NuGet Packages Deliver Time-Delayed Destructive Payloads
Socket researchers discovered nine malicious NuGet packages that use time-delayed payloads to crash applications and corrupt industrial control systems.
@thinkmill/pragmatic-forms
Advanced tools
A pragmatic approach to forms in React (Web and Native)
configureForm: function(options:Object)
initFields: Function(props): { [fieldName: string]: any }submit: Function(formData, props, formProps): Promisevalidate?: Function(formData, props, formProps): { [fieldName: string]: any }onSuccess?: Function(results, props, formProps): voidonError?: FunctiononChange?: Function(formData, props, formProps): voidonFirstInteraction?: Function(formData, props, formProps): voidform Prop
form.isLoading: booleanform.isPristine: booleanform.submitError: anyform.submitResult: anyform.errors: { [fieldName: string]: any }form.hasErrors: booleanform.fields: Objectform.submit: Function(): voidform.reset: Function() :voidform.onSubmit: Function(event?: any) :voidform.onReset: Function(event?: any) :voidform.updateField: Function(name:String, value:any) :voidform.getInputProps: Function(options): InputProps
form.getFieldProps: Function(options): FieldPropsstate (Deprecated)actions (Deprecated)import { configureForm } from '@thinkmill/pragmatic-forms';
const RegistrationForm = configureForm({
initFields: () => ({
name: '',
email: '',
}),
validate: ({ name }) => {
const errors = {};
if (!name) errors.name = 'Please enter a name';
if (!name) errors.email = 'Please enter an email';
return errors;
},
submit: (formData) => {
return fetch('/registration', {
method: 'POST',
body: JSON.stringify(formData),
})
.then(res => res.json());
},
})(({ form }) => (
<form.Form>
{form.hasErrors &&
<div>
<p style={{ color: 'red' }}>Please correct the your input</p>
</div>
}
<input {...form.getInputProps({ name: 'name', type: 'text' })} />
<input {...form.getInputProps({ name: 'email', type: 'email' })} />
<button
type="submit"
disabled={form.hasErrors || form.isLoading}
>
Submit
</button>
</form.Form>
));
When working with pragmatic-forms you will be interacting with either the
configureForm method or the form prop passed to your component.
configureForm: function(options:Object)The pragmatic-forms module exports a single named function: configureForm. This method creates a configured Higher Order Component to wrap a form providing state and event handlers through a single prop named form.
configureForm accepts an options object and returns a method for creating a higher order component which will wrap your form to provide state and event handlers.
initFields: Functionsubmit: Functionvalidate?: FunctiononSuccess?: FunctiononReset?: FunctiononError?: FunctiononFirstInteraction?: FunctioninitFields: Function(props): { [fieldName: string]: any }required
The initFields method will receive props as it's only argument. This method should return an object with key/value pairs that provide the default value for each form field in your form.
Tip: This is a good place to set a default value for a field to avoid the react warning "changing an uncontrolled input of type text to be controlled".
eg.
const withForm = configureForm({
initFields: (props) => ({
name: props.name || '',
email: props.email || '',
}),
...
});
submit: Function(formData, props, formProps): Promiserequired
The submit method will be called with formData, props and formProps and should return a promise.
eg. Trigger a graphql mutation using react-apollo
import { graphql, gql, compose} from 'react-apollo';
import { configureForm } from 'pragmatic-forms';
const query = gql`
mutation createUser (
$name: String!
$email: String!
) {
createUser (user: {
name: $name
email: $email
})
{
id
}
}
`;
export const MyForm = compose(
graphql(query),
configureForm({
initFields: () => ({ name: '', email: '' }),
submit: (formData, props) => {
return props.mutate({
variables: {
name: formData.name,
email: formData.email,
},
});
}
})
)(({ form }) => (
<form onSubmit={form.onSubmit}>
{'...'}
</form>
));
validate?: Function(formData, props, formProps): { [fieldName: string]: any }optional
The validate method receives formData, props and props and returns a map (Object) of errors keyed by the relevant fieldName.
eg.
const withForm = configureForm({
initFields: () => ({ email: '' }),
submit: (formData) => console.log(formData),
validate: (formData, props) => {
const errors = {};
if (!formData.email.includes('@')) {
errors.email = 'Please enter a valid email address';
}
return errors;
},
});
Callbacks provide a way to act on the result of an operation or event within the form. All callbacks are called with an event specific value plus the props passed to the form and the formProps object.
onSuccess?: Function(results, props, formProps): voidoptional
The onSuccess method is called after submit has resolved, the form state has been update and setState has been called.
It receives the result of the submit method, props and formProps as arguments.
onError?: Function(reason, props, formProps)optional
The onError method is called after submit has rejected, the form state has been update and setState has been called.
It receives the rejection reason of the submit method props and formProps as arguments.
onReset?: Function(formData, props, formProps): voidoptional
The onReset method is called on a form reset event after the form has been reinitialised, the form state has been update and setState has been called.
It receives the newly re-initialised formData, props and formProps as arguments.
onChange?: Function(formData, props, formProps): voidoptional
The onChange method is called after the internal setState is complete when any form field has fired it's onChange or onValueChange event.
It receives the complete formData object, props and formProps as arguments.
onFirstInteraction?: Function(formData, props, formProps): voidoptional
The onFirstInteraction method is called when a form fields onChange handler is triggered.
It receives the current formData, props and formProps.
form Propaka formProps
The form prop provides access to the state and methods provided by pragmatic-forms inside your component. The same object is also passed as the last parameter to each of the configureForm methods (excluding initFields).
form.isLoading: booleantrue if the submit method has been called and the promise has not resolved or rejected. Otherwise false
form.isPristine: booleantrue until a change event is triggered on one or more of the forms inputs.
form.submitError: anysubmitError is populated with the rejection reason if the form submit Promise is rejected.
form.submitResult: anysubmitResult is populated with the resolved value (if any) once the forms submit Promise has resolved.
form.errors: { [fieldName: string]: any }Key-value pairs giving the validation errors for each field by field name.
The value will be whatever was returned in the validation method.
form.hasErrors: booleantrue if the validate method returned an error object with at least one property.
form.fields: ObjectProvides access to the form fields as they are stored internally in pragmatic-forms.
Each field will have the following shape:
[fieldName: string]: {
value: 'field value', // :any - whatever you put in here.
isDirty: false, // Boolean - has the field been modified
error: 'some error', // ?String - a field level error message (provided by the `validate` method)
}
form.submit: Function(): voidCalling form.submit will trigger the submit handler directly.
Use cases:
eg. Create a delete button
const withForm = configureForm({
initFields: (props) => ({ id: props.id }),
submit: ({ id }) => {
return fetch(`/item/${id}`, { method: 'delete' });
}
})
const DeleteBtn = withForm(({ form }) => (
<button
type="button"
onClick={form.submit}
disabled={form.isLoading}
>
Delete me
</button>
));
form.reset: Function() :voidCalling form.reset will reset the form to it's original state.
form.onSubmit: Function(event?: any) :voidThe submit event handler. This should be passed as onSubmit to a <form> component.
eg.
const withForm = configureForm({ ... });
const MyForm = withForm(({ form }) => (
<form onSubmit={form.onSubmit}>
...
<button type="submit">Submit</button>
</form>
));
form.onReset: Function(event?: any) :voidThe reset event handler. This should be passed as onReset to a <form> component. When the reset event is triggered, the form will be reset to it's original state.
eg.
const withForm = configureForm({ ... });
const MyForm = withForm(({ form }) => (
<form onReset={form.onReset}>
...
<button type="reset">Reset</button>
</form>
));
form.updateField: Function(name:String, value:any) :voidDirectly update the value of a field by name.
form.getInputProps: Function(options): InputPropsReturns an object with props which can be passed to an input component.
NOTE: For checkboxes it is important to provide the correct type. ie. 'checkbox'. This allows the onChange event handler to check the checked state of the input rather than reading the value.
optionsname: stringtype?: string Defaults to "text"value?:any TODO: Requires explanation.checked?: boolean Whether a checkbox is checked. Defaults to falseforceType?: 'string' | 'number' | 'boolean' undefined by default.If forceType is true, pragmatic-forms will attempt to maintain the primitive type of the initial value of a field. For example, if initFields returns a boolean for the field isEnabled and onChange is called with a string it will attempt to convert that string back to a boolean. This can be helpful when your Input component converts the value field type to a string.
Currently forceType supports string, number and boolean.
InputPropsdisabled: boolean true while the form isLoadingname: string whatever was provided in options.type: string whatever was provided in options. Defaults to textonChange: (event) => void a change handlerchecked: boolean Only for a checkbox or radiovalue Not provided for a checkbox.form.getFieldProps: Function(options): FieldPropsTakes the same options as form.getInputProps.
In addition to the props provided by form.getInputProps this method also returns props which can be used to show more information on a custom component.
error?: string Either a string error message or null if there is no error.isDirty: boolean true when the field has been modified.onValueChange: (value: any) => a special change handler which accepts the value directly rather than via a change event.yarn build will compile the code which can then be either published or yarn linked if you are developing.
To release a new version of run yarn publish. This will run the build script and prompt for a new version number.
Many of the ideas in here are not new. This is a list of some of the places I have taken inspiration from.
FAQs
A pragmatic approach to form handling in React
We found that @thinkmill/pragmatic-forms demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 15 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Research
/Security News
Socket researchers discovered nine malicious NuGet packages that use time-delayed payloads to crash applications and corrupt industrial control systems.

Security News
Socket CTO Ahmad Nassri discusses why supply chain attacks now target developer machines and what AI means for the future of enterprise security.

Security News
Learn the essential steps every developer should take to stay secure on npm and reduce exposure to supply chain attacks.