How do you make a React form start out with some values prefilled when editing?

21 Mar 2017

In an imaginary world where forms are only ever used to enter something from scratch, what you know about forms in React might be enough. In the real world, however, forms are often lively creatures — you can come back to them and change your data.

Up until now, our forms were pretty stand-alone and isolated.

Forms for entering new data start out like this:

constructor() {
  super();
  this.state = {
    email: '',
    password: '',
  };
}

and they are used something like this, perhaps:

<SignUpForm />

We can see they don't receive any props, they keep the current values in the state, and they initialize the state with empty values. Which is perfect if all you need is to collect brand new data through the form.

But what if you had a different form... for editing a post, for example. It would somehow have to accept current title and body. Maybe like this:

<PostForm title={someTitle} body={someBody} />

Except now there are several possibilities as of how to go further with this:

  • Make the form itself fully controlled with regard to its parent. It means instead of keeping its own state, the form is always going to receive field values, as well as callbacks to change them. Just like with controlled/uncontrolled inputs, this will make an entire form controlled.

    <PostForm
      title={...}
      body={...}
      onChangeTitle={...}
      onChangeBody={...}
    />
    

    This is not a usual case, however. Only a subtle fraction of forms out there needs to have something like that. It could be used when the changes to the form, as you make them, need to be immediately reflected in the rest of the app.

    And it's not without its drawbacks, either. Doing it this way means invalid unsaved data now has a way out of the form: if you are directly updating some global state with work-in-progress form values, your app may end up consuming partial or errneous data.

  • Initialize the form state via props. The form will still have its own state with input values. It will simply use the passed field values as a starting point.

    Used as:

    <PostForm title={someTitle} body={someBody} />
    

    The form is going to take initial props, which will be passed to its constructor, and set initial state based on them:

    class PostForm extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          title: props.title || '',
          body: props.body || '',
        };
      }
    }
    

    In a way, this is similar to making the form "uncontrolled" with respect to its parent. It maintains its own state, and uses the passed props as default values of the fields.

    New values should be communicated to the parent when the form is submitted:

    <PostForm
      title={someTitle}
      body={someBody}
      onSubmit={(newTitle, newBody) => { ... }}
    />
    

Unlike with individual inputs, having a form "uncontrolled" is a preferred method to make a form. A form is not a way to change a thing directly, rather, it's a request to change one.

Think about paperwork to change the name. It doesn't directly change your name as you fill it in; it doesn't "bind" to your name. It is just initialized with some data (your current name), and you fill in the new name and take it to bureaucrats before it has any effect.

And the same is often true of forms on the web — they do something only when submitted.

Think your friends would dig this article, too?

Google+
If you need a mobile app built for your business or your idea, there's a chance I could help you with that.
Leave your email here and I will get back to you shortly.