Welcome to the Part 8 of this new series reviewing Cory House’s Pluralsight course Building Applications with React and Flux.
Cory is a Microsoft MVP in C#, founder of OutlierDeveloper.com, avid tech reader, and speaker.
He believes in clean code, pragmatic development, and responsive native UIs.
Building Applications with React and Flux is the prequel to Cory’s course Building Applications with React and Redux in ES6.
Also in this series:
This episode explores the 8th module from this course
We will be considering:
- Reusable inputs
- User notifications
- Saving and Population on load
Create Manage Author Page
We create manageAuthorPage.js with a simple header for starters.
We add a new route into routes.js, and here we specify a path of “author” because we want it to be different from our name of “addAuthor”. This means we can get to this page by adding /author to the end of the URL.
Next we add a link to our new page from our authorPage component. We need to import React-Router here, and reference the Link component.
In our browser we see our new “Add Author” button. This redirects to our new page for adding the author. Next we must create the correct controller view for this page.
Build Controller View
Looking at manageAuthorPage.js, it is tempting to want to add our form HTML into our render function using JSX.
However it is better to instead create a controller view. Our top level components should be smart, but display very little markup.
We create a child component, authorForm.js, to create the form markup, so that our top level component will be smart.
The markup in authorForm is fairly standard, containing a header, inputs and labels, and a submit button.
We import authorForm into manageAuthorPage.js, but we still have an error:
Adjacent JSX elements must be wrapped in an enclosing tag
What this means is there are two top level components in our JSX. There needs to be only one top level function call.
We could wrap both of them in a div tag, but we don’t need the h1 element anymore so we delete it.
Cory shows that our textbox inputs aren’t working: nothing happens when we type!
React automatically redraws the UI on every request animation frame. The textboxes cannot update because there are no change handlers attached to our inputs.
Explicitly creating your change handlers has some benefits.
Cory adds a getInitialState function to manageAuthorPage component, returning an author with empty id, firstName and lastName fields.
This is passed into our render method via props.
This top level component is the best place to handle state changes. Cory adds a setAuthorState method.
This takes the event that has occurred and extracts the field and value. We update state for that field.
We also add an onChange handler in our render function, and this calls our setAuthorState method.
All of this may very well feel like a lot of work just to get a textbox working as you would expect. Cory says that there are a number of different ways to streamline this process.
It is important to realize however, that React values clarity and scalability much more than convention and minimal code. That’s a key trade-off for you to consider when deciding whether React is the framework for you or your organization.
If you really miss Two-Way Binding, there are ways in which you can enable it in React.
Creating Reusable Inputs
Cory points out how much repetition we have in our authorForm.js
He concludes that we need a reusable component for text inputs.
Under our common directory, we create a textInput component.
This is designed to work with Bootstrap, and has a class name which is dynamically created. Bootstrap’s “has-error” CSS class is added whenever there is an error in the props.
Finally, it’s helpful to define PropTypes to make sure everyone knows what data to pass down, and to get warnings if we don’t pass them down.
This is a lot like what we’ve already seen in the React Composition module, but with some extras. We set name, label, onChange, placeholder, value and error.
Consuming Reusable Inputs
We now have a centralized component that we can reuse, and after writing all of that code we can now enjoy the benefits.
We see that our authorForm component is greatly simplified. We see the before and after side by side, and Cory explains why we no longer need all of the code that we’ve just removed.
We see that out authorForm is still working as before. Next we will get the save button working.
In manageAuthorPage.js we add a saveAuthor method, which takes event as its only parameter. We use this to prevent the default browser behavior.
We are just calling a mock API in this course, but once we’ve wired it up, it’s not hard to swap this out for a real API. So here we save our author to our mock API.
We also update our render method with the onSave attribute.
Our save button now works, but it doesn’t give any feedback to the user. What we’d like to happen is to be redirected to the list of authors after we click save. We can do this using React Router.
We see the Navigation mixin that was mentioned a couple of times earlier in this course.
In our saveAuthor method, Cory uses this.transitionTo(‘authors’)
Although we are now redirecting, we also want to notify the user on whether the save was successful.
Cory uses the same solution for this in both of his React courses: John Papa’s Toastr utility.
We see how to install this, and how easy it is to use.
We add validation logic to our form by adding an authorFormIsValid method.
We use simple rules: fields can’t be less than 3 characters, and return a boolean representing whether the form is valid.
Our authorForm component has a lot going on but no PropTypes. Cory add the following PropTypes:
We see that console warnings are generated when a required prop is missing from our render method.
In manageAuthorPage.js, we add a statics object with willTransitionFrom inside it with confirmation and abort logic.
We can update getInitialState to initialize our new dirty flag to false.
Now in the browser we see that when we go to add an author, but then click the home page, it will ask “Leave without saving?”. If we click cancel, then we stay on the same page. If we click OK, then we are redirected to the home page.
One remaining problem is when we try to edit an existing author, their name is not populated in our textbox inputs.
Form Hydration via URL
There’s just 3 simple things left to do:
- Define a route that will handle editing authors – the only difference is the path we use.
- Update the author list component, using the React Router Link component
- Update the Manage Author page with a componentWillMount lifecycle method, to populate the form when it sees the author’s ID in the URL