npm install -s react-fluid-form mobx mobx-react yup lodash
// or:
yarn add react-fluid-form mobx mobx-react yup lodash
I made this library for particular use, because some libraries I used did not satisfy me: formik, mobx-react-form, unform. Some features are inspired by these libs.
The purpose of this library is to be easy to use, with hooks and mobx, which in my use proved to be more performative. Validation is completely optional and customizable. I hope it helps who needs something like this.
I used Mobx for store the state (https://mobx.js.org)
First, you need to create a bind components
object, that tells to library how pass props to field component (like <input />):
const components = {
textInput: {
asValue: "value", // how pass value to field (default is "value")
asChange: ["onChange", ev => ev.target.value], // event for onChange (default is "onChange")
defaultValue: "",
type: String,
asBlur: ["onBlur"] // event for onBlur (default is "onBlur")
},
checkbox: {
asValue: "checked",
asChange: ["onSelect"],
defaultValue: false,
type: Boolean
}
}
After, you need wrap root component with <FormProvider />
, and pass components:
import { FormProvider } form 'react-fluid-form'
function App() {
return <FormProvider components={components}>
// ...your code
</FormProvider>
}
Now, you need call useForm inside your component, that instantiate the form. With instance, you can get the result values, errors, validate programmatically, check validation, and more.
import { useForm } form 'react-fluid-form'
function MyForm() {
const form = useForm({
initialValues: {
} // optional
})
}
Optionally, pass the validator. React fluid form, by default, uses yup
for validation, but you can create your custom validator, or use other libraries. There is no need to use react-fluid-form with validation, just you want.
Example code:
import {useYupValidator, useForm} form 'react-fluid-form'
import * as yup form 'yup'
// Inside component:
// Using yup:
const schema = yup.object().shape({
person: yup.object({
name: yup.string().required()
}).required()
})
const validator = useYupValidator(schema)
const form = useForm({ validator })
// Custom validator:
const validator = function(path, values) {
// params example:
// path: "person.name"
// values: {person: {name: ""}}
const { person: {name} } = values
// If path is undefined, react-fluid-form is validating entire form
if(path) {
// validating specific path of form
if(path === "person.name" && name) {
return "Name of person is required"
}
return ""
}
// validating entire form
if(!name) {
return {
"person.name": "Name of person is required"
}
}
}
import {useForm, Form, Field} form 'react-fluid-form'
function MyForm() {
const form = useForm()
return <Form
form={form}
validateOnBlur // to validate path on blur the field
validateOnChange // to validate path on change
>
// ...
</Form>
}
import {useForm, Form, Field} form 'react-fluid-form'
import {observer} form 'mobx-react'
function MyForm() {
const form = useForm()
return <Form
form={form}
validateOnBlur // to validate path on blur the field
>
<Field
path={"person.name"}
use={"textInput"}
>
<input placeholder={"Name"} />
</Field>
</Form>
}
// Important: for use form instance properties, wrap MyForm in observer (of mobx-react - https://github.com/mobxjs/mobx-react):
export default observer(MyForm)
To show the error on screen, Field pass "error" prop forward. So, you can render in custom input component
Form instance has some helper properties and methods:
Prop/Method | Return type | Description |
---|---|---|
form.isValid |
boolean | Check if the form is valid |
form.result |
object | Get values to save, without mobx observable |
form.errors |
object | Errors object |
form.validateAll() |
void | Validate entire form |
form.validatePath(path) |
void | Validate path of form |
form.setValues(values) |
void | Pass new values to form |
form.setPathValue(path, value, validate) |
void | Set value for specific path |
form.setPathError(path, error) |
void | Set error for specific path |
form.mergeValues(values) |
void | Merge values with new values to form |
form.clear() |
void | Clear form, with initialValues |
form.clearErrors() |
void | Clear errors |
Now, we have useFormChangeEffect hook. Use when you need to call a function, reacting to a change in the value of a field.
useFormChangeEffect((name) => {
console.log("Name changed: ", name)
}, "name", [])
All contributions are welcome. Just make a PR.