Learnings: React and forms

In building DayLog (intro post coming soon), since it's a completely personal project, I've been trying to play with as much new front-end tech as possible. In this instance, I've been finding HTML5 APIs on MDN with poor browser support and trying to find a shim afterwards.

One of the APIs I found was FormData - a nice little library that wraps around a HTML form and gives simple access to element data. For example, in a pseudo React component:

// Copy-and-pasters; don't do this

render() {  
  return (
    <form onSubmit={this.handleSubmit.bind(this)}>
      <label>Name <input type="text" name="name" ref="name" /></label>
      <label>Date of birth <input type="date" name="dob" ref="dob" /></label>
      <button type="submit">Add</button>
    </form>
  );
}

handleSubmit(event) {  
  const data = FormData(event.target);

  fetch('/api/birthdays', {
    method: 'POST',
    body: JSON.stringify({
      name: data.get('name'),
      dob: data.get('dob')
    })
  }).then((resp) => {
    if (resp.statusCode == 201) {
      this.refs.name.value = "";
      this.refs.dob.value = "";
    }
  });
}

This seemed pretty nice. When it came to testing this - I knew it wasn't available on mobile Chrome for example - I ran into issues with shims not working and difficulties in debugging the shims (no remote debug on iOS, Android didn't like to connect).

At this point - I figured it was easier to look up other ways of form handling since I'd have to swap out FormData anyway. It turns out, if only I'd read the docs, I'd have realised this is stateful activity...

constructor(props) {  
  super(props);
  this.state = {name: '', dob: ''};
}

handleInputChange(event) {  
  const target = event.target;
  const value = target.type === 'checkbox' ? target.checked : target.value;
  const name = target.name;

  this.setState({
    // var as object key; search ES6 object literals
    [name]: value
  });
}

render() {  
  return (
    <form onSubmit={this.handleSubmit.bind(this)}>
      <label>Name
        <input type="text" name="name" value={this.state.name} onChange={this.handleInputChange.bind(this)} />
      </label>
      <label>Date of birth
        <input type="date" name="dob" value={this.state.dob} onChange={this.handleInputChange.bind(this)} />
      </label>
      <button type="submit">Add</button>
    </form>
  );
}

handleSubmit(event) {  
  fetch('/api/birthdays', {
    method: 'POST',
    body: JSON.stringify({
      name: this.state.name,
      dob: this.state.dob
    })
  }).then((resp) => {
    if (resp.statusCode == 201) {
      this.setState({name: '', dob: ''});
    }
  });
}

Not news to anyone that read the documentation first, but worth publishing to nudge anyone using FormData this way :-). That said, finding the Fetch API (combined with GitHub's shim) is an example of try-new-stuff working well!