DEV Community

Cover image for Easy React Native Form management with react-formr - DRY
Lakshmeesha
Lakshmeesha

Posted on • Edited on

Easy React Native Form management with react-formr - DRY

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

So here we go with react-formr, 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

A big one

Form with complete available options from formr

// 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>
Enter fullscreen mode Exit fullscreen mode

Shorter version

Using only Formr's inputBinder function


<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>
Enter fullscreen mode Exit fullscreen mode

My Shortest version

The shortest & easiest version is to make a custom input component with error handled inside it.

CustomInput component with error message

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> 
})
Enter fullscreen mode Exit fullscreen mode

Formr form with CustomInput


<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>
Enter fullscreen mode Exit fullscreen mode

Is't it easy??

The Standouts

inputBinder

This function includes almost everything for TextInput 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
Github
react-formr
my github profile

Top comments (0)