npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

reactive-form-react

v1.2.2

Published

Angular like Reactive Forms in React

Downloads

58

Readme

React Reactive Forms

Build Status Backers on Open Collective Sponsors on Open Collective NPM Version code style: prettier

It's a library inspired by the Angular's Reactive Forms, which allows to create a tree of form control objects in the component class and bind them with native form control elements.

Features

  • UI independent.
  • Zero dependencies.
  • Nested forms.
  • Subscribers for value & status changes of controls.
  • Provides a set of validators & also supports custom sync & async validators.
  • FormGenerator api to create large forms with less code.
  • Better form management with FormGroup & FormArray apis.
  • Customizable update strategy for better performace with large forms.

Installation

npm install react-reactive-form --save

Basic Example

import React, { Component } from 'react';
import {
    FormBuilder,
    FieldGroup,
    FieldControl,
    Validators,
 } from "react-reactive-form";

const TextInput = ({ handler, touched, hasError, meta }) => (
  <div>
    <input placeholder={`Enter ${meta.label}`} {...handler()}/>
    <span>
        {touched
        && hasError("required")
        && `${meta.label} is required`}
    </span>
  </div>  
)
export default class Login extends Component {
    loginForm = FormBuilder.group({
        username: ["", Validators.required],
        password: ["", Validators.required],
        rememberMe: false
    });
    handleReset=() => {
        this.loginForm.reset();
    }
    handleSubmit=(e) => {
        e.preventDefault();
        console.log("Form values", this.loginForm.value);
    }
    render() {
        return (
              <FieldGroup
                control={this.loginForm}
                render={({ get, invalid }) => (
                  <form onSubmit={this.handleSubmit}>

                    <FieldControl
                      name="username"
                      render={TextInput}
                      meta={{ label: "Username" }}
                    />

                    <FieldControl
                      name="password"
                      render={TextInput}
                      meta={{ label: "Password" }}
                    />

                    <FieldControl
                      name="rememberMe"
                      render={({handler}) => (
                        <div>
                          <input {...handler("checkbox")}/>
                        </div>
                      )}
                    />
                    <button
                      type="button"
                      onClick={this.handleReset}
                    >
                      Reset
                    </button>
                    <button
                      type="submit"
                      disabled={invalid}
                    >
                      Submit
                    </button>
                  </form>
                )}
              />
        );
    }
}

Using FormGenerator

import React, { Component } from 'react';
import {
    Validators,
    FormGenerator
 } from "react-reactive-form";
// Input component
const TextInput = ({ handler, touched, hasError, meta }) => (
  <div>
    <input placeholder={`Enter ${meta.label}`} {...handler()}/>
    <span>
        {touched
        && hasError("required")
        && `${meta.label} is required`}
    </span>
  </div>  
)
// Checkbox component
const CheckBox = ({ handler }) => (
    <div>
      <input {...handler("checkbox")}/>
    </div>
  )
// Field config to configure form
const fieldConfig = {
    controls: {
        username: {
            options: {
                validators: Validators.required
            },
            render: TextInput,
            meta: { label: "Username" }
        },
        password: {
            options: {
                validators: Validators.required
            },
            render: TextInput,
            meta: { label: "Password" }
        },
        rememberMe: {
            render: CheckBox
        },
        $field_0: {
            isStatic: false,
            render: ({ invalid, meta: { handleReset } }) => (
                <div>
                    <button
                      type="button"
                      onClick={handleReset}
                    >
                      Reset
                    </button>
                    <button
                      type="submit"
                      disabled={invalid}
                    >
                      Submit
                    </button>
                </div>
            )
        }
    },
}
export default class Login extends Component {
    handleReset=() => {
        this.loginForm.reset();
    }
    handleSubmit=(e) => {
        e.preventDefault();
        console.log("Form values", this.loginForm.value);
    }
    setForm = (form) => {
        this.loginForm = form;
        this.loginForm.meta = {
            handleReset: this.handleReset
        }
    }
    render() {
        return (
            <form onSubmit={this.handleSubmit}>
                <FormGenerator
                    onMount={this.setForm}
                    fieldConfig={fieldConfig}
                />
            </form>
        );
    }
}

Add Controls Dynamically

You can also create controls without even initializing the group control object with the help of new react form components ( FieldGroup, FieldControl, FieldArray).

import React, { Component } from 'react'
import { FieldGroup, FieldControl, Validators } from 'react-reactive-form'

export default class Login extends Component {
  handleSubmit = (e, value) => {
    console.log('Form values', value)
    e.preventDefault()
  }
  render() {
    return (
      <FieldGroup
        render={({ get, invalid, reset, value }) => (
          <form onSubmit={e => this.handleSubmit(e, value)}>
            <FieldControl
              name="username"
              options={{ validators: Validators.required }}
              render={({ handler, touched, hasError }) => (
                <div>
                  <input {...handler()} />
                  <span>
                    {touched && hasError('required') && 'Username is required'}
                  </span>
                </div>
              )}
            />
            <FieldControl
              name="password"
              options={{ validators: Validators.required }}
              render={({ handler, touched, hasError }) => (
                <div>
                  <input {...handler()} />
                  <span>
                    {touched && hasError('required') && 'Password is required'}
                  </span>
                </div>
              )}
            />
            <FieldControl
              name="rememberMe"
              render={({ handler }) => (
                <div>
                  <input {...handler('checkbox')} />
                </div>
              )}
            />
            <button type="button" onClick={() => reset()}>
              Reset
            </button>
            <button type="submit" disabled={invalid}>
              Submit
            </button>
          </form>
        )}
      />
    )
  }
}

So, it's not mandatory that you need to define your control separately but if you want a better control over your form state then you should do that, if your controls are dynamic then you can also initalize the empty group control and add the controls later. See the example:

import React, { Component } from 'react'
import {
  FormBuilder,
  FieldGroup,
  FieldControl,
  Validators
} from 'react-reactive-form'

export default class Login extends Component {
  // Initialize the empty group control
  loginForm = FormBuilder.group({})

  handleReset = e => {
    this.loginForm.reset()
  }
  handleSubmit = e => {
    console.log('Form values', this.loginForm.value)
    e.preventDefault()
  }
  render() {
    return (
      <FieldGroup
        control={this.loginForm}
        render={({ get, invalid, reset, value }) => (
          <form onSubmit={this.handleSubmit}>
            <FieldControl
              name="username"
              options={{ validators: Validators.required }}
              render={({ handler, touched, hasError }) => (
                <div>
                  <input {...handler()} />
                  <span>
                    {touched && hasError('required') && 'Username is required'}
                  </span>
                </div>
              )}
            />
            <FieldControl
              name="password"
              options={{ validators: Validators.required }}
              render={({ handler, touched, hasError }) => (
                <div>
                  <input {...handler()} />
                  <span>
                    {touched && hasError('required') && 'Password is required'}
                  </span>
                </div>
              )}
            />
            <FieldControl
              name="rememberMe"
              render={({ handler }) => (
                <div>
                  <input {...handler('checkbox')} />
                </div>
              )}
            />
            <button type="button" onClick={this.handleReset}>
              Reset
            </button>
            <button type="submit" disabled={invalid}>
              Submit
            </button>
          </form>
        )}
      />
    )
  }
}

Documentation

Code Sandboxes

Try out react-reactive-forms in these sandbox versions of the Examples.

FAQ

How is it different from other form libraries?

React has many libraries which works on the form logic, but here are some concerns with these:

Code Complexity

If you’re using the redux-form then you should know the pain, for just a two field login form you’d to write the store logic.In RRF you can see that how simple is to deal with simple and complex forms.

And one of the awesome thing is that you can just write your form controls logic anywhere in your application.

Dependencies

Many libraries come with dependencies for e.g redux is required for redux-form, So what If I’m using another state management or not event using any. According to Dan Abramov, form state is inherently ephemeral and local, so tracking it in Redux (or any kind of Flux library) is unnecessary. RRF comes with zero dependency, So it’s totally up to you that how you want to save your form state if needed.

Performance

Now that’s a big problem with almost all libraries when you're dealing with large forms.

How RRF does solve performance issues ?

  • It uses subscription to update the components so rather updating all the fields on every input changes, it only update the particular field for which the state change takes place.
  • RRF has a nice option to define that when(blur, submit or change) to update your form's state by using the updateOn property.

Dynamic Changes

With the help of subscribers it's pretty easy to listen for a particular state changes and modify the controls accordingly.

What are value and status changes subscribers?

RRF uses inbuilt Subject, A Subject is an object with the method next(v).To feed a new value to the Subject,RRF just calls the next(theValue), and it will be multicasted to the Observers registered to listen to the Subject. So basically it provides three subjects for each AbstractControl valueChanges, statusChanges and stateChanges and additional two subjects for FormControl ( onValueChanges, onBlurChanges) You can register an observer to a particular Subject to do some actions whenever some particular changes happen.

Example:

componentDidMount() {
  this.myForm.get(“gender”).valueChanges.subscribe((value) => {
    // do something
  })
}

Checkout the Basic usage guide for more details.

How the Field components work?

Field components are subscribed to the state changes of a particular control which means that it’ll re-render the component only when it’s state changes disregarding of other field changes.You can also implement your custom wrappers by using the stateChanges Subject.

How updateOn feature works?

Its an another performance booster in RRF, it just holds the computation needed to be made after every keystroke or value changes until you want to execute.It has three options change(default), blur and submit, you can define all of them at both field and record level.

Is this library compatible with React Native?

Yes, this library works with react-native also, currently it supports react-native TextInput and Switch component.

Note:

If you're using react-native then please add the following line of code in index.js of your project to avoid error in android devices.

import "core-js/es6/symbol";
import "core-js/fn/symbol/iterator";

Let's make React Reactive Forms better! If you're interested in helping, all contributions are welcome and appreciated.

And don't forget to star the repo, I will ensure more frequent updates! Thanks!

Contributors

This project exists thanks to all the people who contribute.

Backers

Thank you to all our backers! 🙏 [Become a backer]

Sponsors

Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [Become a sponsor]