Easy React Native Form management with react-formr - DRY
Tags: reactnative, npm, react, javascript
Published: 2020-09-23 18:52:50

**Managing form values, validation, focus & submission is kind of boring & pain** we all know that. But if we can centralise that form management stuff to one package, that will be good enough for developer to think and develop something important than this.

> Don't reapeat yourself is a thing, There are many plugins available at ease, But...

The plugins i have seen before are more into react oriented than the react native. like formik, it dont have anything specific binder to react-native, again we have to give all values or hndling functions separately & again we need to manage focus in our code. 

# A solution - **react-formr**
[![react-formr](https://dev-to-uploads.s3.amazonaws.com/i/cikxwobk497wq3dyof1z.png)](https://www.npmjs.com/package/)

So here we go with [react-formr](https://www.npmjs.com/package/), a package is written for react native. 

## Features
1. Form validation on given rules (regex) or predefined types(email, phone, etc).
2. Input binder function includes almost everything `TextInput` required to handle form.
3. Auto focus next available input on return press, triggering `onFocuseFinish` on last input return key press.
4. Input blur validation & validate on change of invalid input.
5. Listen to live changes in form using `onChange` props.
6. Written with Typescript
7. Not limited to TextInput, it can be used anything with handle value change & values object.

> **Update**: `useFormr` hook is available now, no need to wrap the form with Formr component anymore.

## Let's jump into using it
first & foremost  - **installation**
`yarn add react-formr` or `npm install react-formr`
[react-formr](https://www.npmjs.com/package/react-formr)
### A big one
Form with complete available options from formr
```javascript
// Formr form manager wrapper
<Former 
	onChange={(values)=>{
			// Triggers if any value change in form
			console.log(values)
		}}
	onFinishFocus={(values)=>{
		// Triggers all form fields finished focusing
			console.log(values)
		}}
	formFields={{ password: "" }} //Initial value can be added here
        validation={{
          password: {
            required: true,
            rules:
              "0-9])(?=.*[a-z].*[a-z].*[a-z]).{8}$",
          }
        }} >
        {// Provides a function to render form inputs }
        {({
          inputBinder, // Package of TextInput props
          onChangeHandler, // included in inputBinder
          values, // included in inputBinder
          onBlurHandler,// included in inputBinder
          onSubmitHandler,
          onSubmitEditingHandler,
          refsHandler,// included in inputBinder
          touched,// included in inputBinder if you are making custom input component with this props
          valid,// included in inputBinder if you are making custom input component with this props
        }) => {
          return (
            <View
              style={{
                flex: 1,
                marginTop: 50,
              }}>
                <TextInput
                  style={{
                    borderColor:
                      valid.email != null && touched.email && !valid.email
                        ? "red"
                        : "black",
                    ...styles.input,
                  }}
                  value={values.password}
                  ref={(ref)=>refsHandler('password',ref)}
                  onBlur={()  =>  onBlurHandler('password')}
                  onChangeText={text=>onChangeHandler('password',text)}
		            onSubmitEditing={()=>onSubmitEditingHandler('password')} 
                />
                <Button onPress={()=>onSubmitHandler(value=>submitIt(value))} />
              </View>
	         )//end of return
	       }// end of formr function
       }
</Formr>
```
### Shorter version
Using only Formr's **inputBinder** function
```javascript

<Former formFields={{ password: "" }}
        validation={{
          password: {
            required: true,
            rules:
              "0-9])(?=.*[a-z].*[a-z].*[a-z]).{8}$",
          }
        }} >

        {({
          inputBinder, 
          onSubmitHandler,
          touched,
          valid
        }) => {
          return (
            <View
              style={{
                flex: 1,
                marginTop: 50,
              }}>
                <TextInput
                  style={{
                    borderColor:
                      valid.email != null && touched.email && !valid.email
                        ? "red"
                        : "black",
                    ...styles.input,
                  }}
                  {...inputBinder("email")} // THIS IS WHERE THE DIFFERENCE COMES
                />
                <Button 
                   onPress={()=>onSubmitHandler(value=>submitIt(value))} 
/>
              </View>
	         )//end of return
	       }// end of formr function
       }
</Formr>
```
### My Shortest version
The shortest & easiest version is to make a custom input component with error handled inside it.

#### CustomInput component with error message
```javascript
const CustomInput = React.forwardRef(({valid,value,touched,errorMsg,...rest},ref)=>{
	const showError = value!=="" && valid && touched;
	return(
	<View>
		<TextInput 
			{...rest} 
                        ref={ref}
			value={value} 
			style={
			borderWidth:1,
			borderColor:showError?"red":"gray",
			...rest.style} 
		/>
		{showError && <Text style={color:"red"} >{errorMsg}</Text>}
	</View>	
})
```
#### Formr form with CustomInput
```javascript

<Former formFields={{ email: "" }}
        validation={{
          password: {
            required: true,
            type:"email"
          }
        }} >
        {({
          inputBinder, // Package of TextInput props.
          onSubmitHandler, // For submitting form.
        }) => {
          return (
            <View
              style={{
                flex: 1,
                marginTop: 50,
              }}>
                <CustomInput 
	                {...inputBinder("email")} 
	                errorMessage="Something is wrong here" 
	             />
                <Button onPress={()=>onSubmitHandler(value=>submitThis(value))} />
              </View>
	         )//end of return
	       }// end of formr function
       })
</Formr>
```

Is't it easy??

### The Standouts
#### `inputBinder`
This function includes almost everything for <b>`TextInput`</b> to manage form with inputs, They are - `value`, `onChangeText`, `onBlur`, `ref`, `onSubmitEditing` also `valid` & `touched` if you are making custom input component with these props .
#### `validation` 
Receives object with predefined commonly used **type** or regex **rules** to validate, also we can mention **required** field here, Option of providing rules to the input is unlimited with regex.
#### Auto focusing input
Unlike react form plugins, as it is built for react-native, it handles focusing next input (or the element have ref & handles focus) easily. Let's see more about this in next topic.

# Common problems & solutions
### Auto focusing next input with ref
The best user experience is to focus next available input on next button press in already visible keyboard, Nobody wants to touch all available inputs to fill the form. that is kind of must for all forms now. The problem here to manage refs of input & focusing them with `onSubmitEditing`. 
Formr solves this hassle by maintaining refs inside it & focusing next ref on submitHandler.
### Managing Validation 
Yes, Managing validation with multiple input will go very long or unexpectedly complicated. Every field with its own type of validation handling, need to handle touched states to show error after interaction, it will become hefty if we don't plan it properly.
Formr has the thing what we don't want to write it again & again. One package handles touch state management, validation cycles, focus events for validations & so on. it also validates fields on any value change or submit press, updates valid object, it focuses untouched input fields.
### Managing form values
We might need to maintain multiple states for input values, that is kind of too much if we are trying to make a function to update all & validate.
Formr receives initial values, manages it on update of any form fields, provides values object in multiple places, i.e. in form render function as values, in `onSubmit`, in `onFinishFocus` prop, in `onChange` prop.

# Final
While i was working with my projects, i felt that I'm writing something repeatedly & unnecessarily. If i try to go for any plugins to do it, has its own learning curve & road blocks or i have to use multiple plugin to do 1 form, that is little too much to handle later. So this, I have created a package to share with everyone of you. Suggest me if anything i can improve in this.
**NPM**
[react-formr](https://www.npmjs.com/package/react-formr)
**Github**
[react-formr](https://github.com/ltsharma/react-formr)
[my github profile](https://github.com/ltsharma/react-formr/commits?author=ltsharma)