React / Form component

As you probably already know React is quite a new gamer in SPA world. In contrast to AngularJS it prefers functional approach to deal with complex and interactive UI. After creating two projects with Angular I decided to try it out with my new application. I will describe overall impression later, here I want to share my problems with form component.

My application consists of many forms like settings, user profile, registration panel etc. Each of them:

  • has input elements and submit button
  • loads initial data via ajax
  • stores entered data via ajax
  • blocks form during ajax calls
  • has nice progress indicator

I could create each of those form in classical way described in react documentation but that would be cumbersome and generated too much code. This is what I wanted to achieve:

Every kind of html input is wrapped in a react component that stores input type, its value and other necessary parameters as well as internal state if component is a little bit complex. Then Form component iterates over its children, creates validation rules for validation plugin (which in my case comes from http://semantic-ui.com) and responds to submit button. Form component is also responsible for loading and saving form data from url passed through url attribute.

I was really surprised that such a functionality is impossible to achieve in react (at least in current version). Of course that might be my fault and I would be thankful if someone shared a similar component that is working. So what is the problem? The problem is parent – children communication. Let’s take a look at a Form component (simplified version):

The most interesting part is {this.props.children}. In this property all the tags between <Form></Form> declared in PersonalDataForm are passed. One can iterate over them using React built in functions. Here’s my iteration helper (react’s foreach looks for children only one level deep in dom hierarchy):

Unfortunately (in this case) Form component is not the owner of those children. The PeronalDataForm is. That has consequences. I can’t in Form update the children properties or transfer properties passed to Form (it’s a problem because this is the preferred way of communicating with children in react). Also if I would like to modify state of children I’m forced to use undocumented internals of react (that can change in feature versions) like __realComponentInstance (if that only worked 🙂 , the render method of child component still used previous state). What worked in the code above was validation as reading data from this.props.children was perfectly fine. What didn’t work was modifying props or state of children. I wasn’t able to load data from server and distribute it among children from within Form component.

I hope in future version communicating between children and parent will be addressed in some way or another. In the meantime I used mixins. Now PersonalDataForm looks like this:

I simply inlined all the methods that previously were placed in the Form component into the PersonalDataForm. Now PersonalDataForm is the owner of all inputs and is able to manipulate them. I also gave up on iterating over children through this.props.children. Now I iterate over this.refs. That simplifies the code but requires providing ref attribute at every input wrapper. Another disadvantage is forcing user to mix in FormMixin in every form component and unnecessary code duplication because of that. User also has to pass this.state.data (which contains ajax data) everywhere, but the final effect is very similar to what I really wanted. I will post sources of my components soon.

Leave a Reply

Your email address will not be published. Required fields are marked *