The React way of thinking

We believe that React is the foremost tool for building fast, big web applications. Our Facebook and Instagram pages have benefited greatly from it.

When building an app with React, you have to think of the app as a whole. We will cover the steps involved in building a searchable product data table using React in this document.

Start With A Mock

Assume we already have a JSON API and a mock from our designer. An example of a mockup is this:

Mockup

Our JSON API returns the following data:

[

  {category: “School Goods”, price: “$59.99”, stocked: true, name: “Books”},

  {category: “School Goods”, price: “$11.99”, stocked: true, name: “Notebook”},

  {category: “School Goods”, price: “$30.99”, stocked: false, name: “Uniform”},

  {category: “Gadgets”, price: “$100.99”, stocked: true, name: “Airpods”},

  {category: “Gadgets”, price: “$300.99”, stocked: false, name: “iPhone 12 Pro”},

  {category: “Gadgets”, price: “$200.99”, stocked: true, name: “iPhone X”}

];

Step 1: Structuring The UI Through Component Hierarchies

The first thing you’ll want to do is to draw boxes around every component (and subcomponent) in the mock and give them all names. If you’re working with a designer, they may have already done this, so go talk to them! Their Photoshop layer names may end up being the names of your React components!

But how do you know what should be its own component? Use the same techniques for deciding if you should create a new function or object. One such technique is the single responsibility principle, that is, a component should ideally only do one thing. If it ends up growing, it should be decomposed into smaller subcomponents.

Since you’re often displaying a JSON data model to a user, you’ll find that if your model was built correctly, your UI (and therefore your component structure) will map nicely. That’s because UI and data models tend to adhere to the same information architecture. Separate your UI into components, where each component matches one piece of your data model.

Component diagram

Our app has five components, as you can see here. Each component’s data has been italicized.

FilterableProductTable (orange): contains the entirety of the example

SearchBar (blue): receives all user input

ProductTable (green): displays and filters the data collection based on user input

ProductCategoryRow (turquoise): displays a heading for each category

ProductRow (red): displays a row for each product

If you look at ProductTable, you’ll see that the table header (containing the “Name” and “Price” labels) isn’t its own component. This is a matter of preference, and there’s an argument to be made either way. For this example, we left it as part of ProductTable because it is part of rendering the data collection which is Product Tables responsibility. However, if this header grows to be complex (e.g., if we were to add affordances for sorting), it would certainly make sense to make this its own ProductTableHeader component.

Now that we’ve identified the components in our mock, let’s arrange them into a hierarchy. Components that appear within another component in the mock should appear as a child in the hierarchy:

FilterableProductTable

SearchBar

ProductTable

ProductCategoryRow

ProductRow

Step 2: Create a static variant in React

Your component hierarchy is now ready for implementation. To build a version that renders your data model but does not have interactivity, you can build a version that takes your data model and renders the UI. Adding interactivity requires a lot of thinking while creating a static version requires a lot of typing. Let’s find out why.

You will want to create components that reuse other components and pass data via props to build a static app that renders your data model. Props are a means of passing data between children and parents. You shouldn’t use the state to build this static version if you’re familiar with the concept of state. Data that changes over time is considered state and is reserved for interactive data. You do not need this version of the app since it is static.

It is possible to build top-down or bottom-up. You can either start with the components higher in the hierarchical structure (such as FilterableProductTable, for instance) or lower in the hierarchy (ProductRow). If your project is simpler, you can go top-down; if it is more complex, you will need to build bottom-up and test as you go.

Your data model will be rendered using reusable components after this step. As this is a static version of the app, all of the components will have render() methods. Data models are props for the topmost component (FilterableProductTable). In this situation, the UI will be updated if you call ReactDOM.render() again after changing your underlying data model. This enables you to see where to make changes to your UI. One-way data flow (also known as one-way binding) keeps everything modular and fast in React.

Putting Props vs. State into Context

React has two types of “model” data: props and state. As part of React, props are variables that are passed to the component from its parent component. The state, on the other hand, is a variable, but it is directly initialized and managed by the component. Initializing the state can be done via props.

Step 3: Find a minimal (but complete) representation of UI state

It’s crucial that you can trigger changes to your underlying data model so that your UI can be interactive. The state allows React to achieve this.

First, you need to figure out what minimal set of mutable state your app requires. In this case, the key is DRY: Don’t Repeat Yourself. Calculate everything else you need based on the state your application needs, and then find the minimum representation of that state you need. As an example, if you’re building a task list, you should keep an array of all the items; do not store a separate variable for the number of items. You should instead take the length of the task items array when rendering the task count.

Just imagine all the information that our example application has to offer. What we have is:

A list of the original products

User-inputted search text

Checkbox value

Products sorted by the filter

As we go through each, let’s identify which is the state. Consider the following three questions for each piece of data:

Are props passed in from a parent? Then it is probably not a state.

Is it unchanged over time? Then it is probably not a state.

Is it possible to compute it based on any other state or prop in your component? Therefore, it does not fall under the state umbrella.

Originally, a list of products is passed in as a prop, so that is not a state. There are no algorithms that can compute the search text and the checkbox as they change over time. Last but not least, the filtered list of products doesn’t constitute a state because it is simply the result of combining the original list of products with the search text and value of the checkbox.

So finally, our state is:

The search text the user has entered

The value of the checkbox

Step 4: Decide where your state should reside

OK, so we’ve identified what the minimal set of app state is. Next, we need to identify which component mutates, or owns, this state.

React is all about one-way data flow down the hierarchy of components. Identifying which component owns which state may not be obvious at first. The most challenging part of this is often figuring this out, so know these steps:

As you develop your application, keep the following state in mind:

Determine which components render something based on that state.

In your hierarchy, find the component with the most common owner (the component one component above the others).

Ownership of the state should either be assigned to the common owner or to another higher component.

When a component doesn’t make sense to own the state, you can create a new component that holds the state exclusively and add it somewhere in the hierarchy above the common owner component.

The following strategy will help us with our application:

ProductsTable should filter product lists according to their states and SearchBar should display the search text and the checked status.

FilterableProductTable is the common component owner.

The filter text and checked value should reside in FilterableProductTable conceptually.

We have decided to put state within our FilterableProductTable. Add the following property to the instance: this.state = {filterText: ”, inStockOnly: false} in the constructor of FilterableProductTable to reflect the initial state of the application. After that, pass filterText and inStockOnly as parameters to ProductTable and SearchBar. Additionally, set the values of the form fields in SearchBar using the props for ProductTable and SearchBar.

Setting filterText to “ball” will give you a preview of how your application will behave. Upon opening the data table, you will see that the update has been made correctly.

Step 5: Create a reverse data flow

Currently, we have built a renderer that works when props and state flow down the hierarchy. Likewise, data must flow the other way: deep in the hierarchy, the form components have to know how to update the FilterableProductTable.

Data flow in React is explicit to help you understand how your program works, but it does require a bit more typing than traditional two-way data binding.

You will see that React ignores your input if you attempt to type or check the box in the current version of the example. Keeping the value prop of the input constant, we have set the value prop to reflect the state passed in from FilterableProductTable.

Here are a few things we should consider. Our goal is to update the form state every time the user makes a change. In order to ensure that each component updates its own state independently, FilterableProductTable passed callbacks to SearchBar that fire whenever the state change occurred. By using the onChange event on the inputs, we can be notified of the change. Upon receiving calls from FilterableProductTable, the app will update its state using setState().

This concludes the idea

This should give you an idea of how to think about building components and applications with React. This may seem like an extra step, but remember that code is read much more than it’s written, and it’s easier to read this modular, explicit code. With this explicitness and modularity developing within your components library, your lines of code will get smaller and smaller as you start to develop large libraries of components.

Leave a Reply

Your email address will not be published.