Building reusable components with React
React creates components that render themselves using their own properties (props) and states (state). Using this components you can create reusable, robust and dynamic state elements for your HTML.
The first thing you would want to do is create a mock of the screen you want to build. From here you can start by drawing boxes around every component and subcomponent you think you may need. The more you play around with React the better you will become at identifying what is a component and the best hierarchy they should follow.
I single out 6 components:
- FilterablePlayersTable: contains the entirety of the example
- PlayerTable: renders the table
- PlayerRow: renders each row of the table
- SearchArea: receives all user input
- FilterRace: area that contains the Race filter checkboxes
- FilterRaceCheckbox: the checkbox for filtering by race
The hierarchy would look something like this:
- FilterablePlayersTable (blue)
- PlayerTable (green)
- PlayerRow (teal)
- SearchArea (yellow)
- FilterRace (orange)
- FilterRaceCheckbox (pink)
- FilterRace (orange)
- PlayerTable (green)
You could make a case that the table headers could be their own component if we wanted to, for example, order by each column on click. For this basic example, I won’t be doing that. By the end of this post you should be able to add that functionality on your own, if you feel like it.
Now that I have the component hierarchy, it’s time to build the initial static version of the app. For now I just want to render the components. As React docs say: building a static version requires a lot of typing and no thinking, and adding interactivity requires a lot of thinking and not a lot of typing.
For the table, I’ll use Jack Rugile’s style, because it looks cool. Except with no blur effect on hover.
You can start building top-down or bottom-up. This means starting by the highest hierarchy component (FilterablePlayersTable) or starting by the lowest hierarchy component (PlayerRow or FilterRaceCheckbox).
I prefer to build bottom-up, as every new component depends on the one just created before it and you can easily write tests for each individual component.
As each React.Component renders itself, each will have it’s own render() method. This is where we put the HTML code that the component will have on the page. The way React works you can render common HTML stuff, like divs, or you can render other React components.
Once the components have their proper render methods, the general outlook of the app is ready. All changes we make from here on out will not alter this structure, only improve it.
React is so good at reusing components that you can easily add new stuff with minimal effort.
For example, try editing this CodePen. Go to the hard coded array RACES that represents the server input. Now try adding a new String to the array. Once the Pen recompiles you will see that a new checkbox has been created with the value you just added. React magic.
Now that we have working visuals, it’s time to work on the functionality.
React uses two main things: props and states. Props can be passed down to child components are are usually used for rendering specific values, like data on a table row.
In this case, each row will render a specific Player from the JSON we receive, so this prop will have to be passed down to PlayerTable, where I can iterate over the Players and create a PlayerRow for each and every one of them.
This props are immutable. The only time a Player’s data will change is when a new JSON array is received.
For changing values, we use “states”. In this case, the components that will be changing over time are the filters. The table will change according to the filter’s states, so the actual state will have to be saved on the highest shared parent (in this case FilterablePlayersTable) so that it can be passed down from the checkboxes to the table.
What I want to do is filter the table by name with the input text field and filter the table by race when a race checkbox is changed.
To achieve this I will have to bind a function to a prop. React lets me do this. So now I bind a function that sets a prop of the SearchArea component as the input of the text field to the onChange event of the HTML Input element. Remember when I said that props were not supposed to change? The exception is when you need to pass the value to a parent. On the parent component I can create a function that handles the change in state and assign it to the prop I just changed in the SearchArea. I can just keep chaining props and functions until I reach the shared parent component needed to pass down the state to the table.
For the reverse path, I send down the state to the child components until I reach the table.
On the render method I apply the logic to filter the table according to the state I receive.
And there we go! All components are rendered and functional. Try adding a new Race to the initial input and add a new entry to the players with that race. You will see that the checkbox filter works perfectly.
Next time I’ll review how to integrate this component oriented frontend to some backend framework.