Socket
Socket
Sign inDemoInstall

react-form-state

Package Overview
Dependencies
2
Maintainers
1
Versions
12
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

    react-form-state

It's all about you already know about controlling the state inside a component, but made easier to write expressive data-driven forms.


Version published
Maintainers
1
Install size
648 kB
Created

Readme

Source

Form-State

A straightforward form management

It's all about you already know about controlling the state inside a component, but made easier to write expressive data-driven forms.

You will not have to learn a new way of doing things as many libraries out there does today. Form-State can be seen as just as a small package that helps you with forms without extra overheading components.

Built on top of some lodash/fp functions, this library provides immutability out of the box with.

Background

This library is built with these principles in mind:

  • Keep data immutable
  • Avoid extra components, render functions or new syntax
  • Configuration over code
  • setState only when needed
  • Keep track on form errors
  • Only send the changes made
  • DRY

That being said and in order to keep a straightforward form component, the first thing we do is define the schema that the form is based on (configuration over code). To achieve that, we use Joi to write it down, but also to normalize and validate the data. It's a very powerful library with a clean syntax that makes you understand all of your form should provide in a breeze. [https://github.com/jeffbski/joi-browser]

Installation

yarn add react-form-state

Usage

  import Form from 'react-form-state';

Coupling the form state inside a component state is just as easy as defining three objects in it.

  state = {
    form: {},
    changes: {},
    errors: {}
  };

See? No magic. You can also use a shortcut

  state = {
    ...Form.defaultState
  };

The form object keeps the raw user input. changes holds all the data that was modified and is valid! errors is, well, the errors. Next, provide a schema that your form is based on.

  schema = {
    firstName: Joi.string().min(5).required(),
    email: Joi.string().email().required(),
    age: Joi.number().min(0).max(100).required()
  }
class ProfileForm extends React.Component {
  constructor(props) {
    super(props);
    this.form = new Form({ schema });
    this.state = { ...Form.defaultState };
  }
}

Form-State manages a small state inside of it. Its changes reflects back to the component state. Thus, let's provide a hook that make those changes happen. It's not required though, all form methods returns a new state object that you can manually merge into yours component state, if you want to. You are in charge.

class ProfileForm extends React.Component {
  constructor(props) {
    super(props);
    this.form = new Form({ schema, onChange: this.onFormChange });
    this.state = { ...Form.defaultState };
  }

  onFormChange = (formState) => this.setState({ ...formState });
}

formState wraps form, changes and errors as we defined before. A shallow merge into the component state is just fine, as Form-State already handle nested changes and creates new objects everytime they have been modified, guaranteeing immutability.

Finally, let's bring the form and put it all togheter.

class ProfileForm extends React.Component {
  constructor(props) {
    super(props);
    this.form = new Form({ schema, onChange: this.onFormChange });
    this.state = { ...Form.defaultState };
  }

  onFormChange = (formState) => this.setState({ ...formState });

  render() {
    const { errors, form: profile } = this.state;
    const canSubmit = this.form.hasChanges() && !this.form.hasErrors();
    return (
      <div>
        <label for="firstName">First Name {errors.firstName}</label>
        <input name="firstName" value={profile.firstName}
          onChange={this.form.handleChange} />

        <label for="email">Email {errors.firstName}</label>
        <input name="email" value={profile.email}
          onChange={this.form.handleChange} />    

        <label for="age">Email {errors.age}</label>
        <input name="age" value={profile.age}
          onChange={this.form.handleChange} />

        {canSubmit && <button onClick={this.handleSubmit}>Submit!</button>}
      </div>
    )
  }
}

Your handleSubmit function can be simple as just grabbing the changes object and dispatching it to the server. For example, if you are using redux:

  handleSubmit = () => {
    const { changes } = this.state;
    this.props.dispatch(saveProfile(changes));
  }

Peforming setState manually on form changes

Form-State holds a brief state so every time a field changes, it can perform all tasks involved to validate the data, merge the errors, raw and the normalized input to, finally call the trigger that will eventually call setState in the component. This is done all by once, so the setState will be called only once also, and you won't have to write waterfall setState's for every possible change.

On the other hand, you can easily get to the bare metal here.

  handeChange = (event) => {
    const { name, value } = event.target;
    const newState = this.form.set(name, value);
    this.setState({ ...newState });
  }

As set peforms triggers the input validation, you can also merge the data you want, if you need bypass any validation.

  checkName = (name) => {
    if (name === 'john') {
      const errors = { firstName: 'already exists!' };
      const newState = this.form.merge({ errors });
      this.setState({ ...newState });
    }
  }

Or even update (replace) a whole form state. Be in mind that with great powers comes great resposabilities.

Common pitfalls

Keep in mind that every time you manually peform a changing in the form state that you want both, the user see the changes feedback and set these changes to be commited when submitting the form, you need to merge/update form and changes sub states.

If you are adding extra data in the form state that is not defined in the schema, this library won't track its errors and so will not clear them by itself, if you are setting any. You will have to manage it too.

Nevertheless, you don't need to be worry about using the onFormChange trigger and managing some extra data by yourself. react-form-state will only clear errors for fields that are defined on the schema.

Initializing the form

Custom error messages

Dynamic inputs

FAQs

Last updated on 12 Mar 2018

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.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc