If you're a back-end developer getting into frontend dev space via React, the UI library can feel strangely weird or just outright foreign. Or if you're a front-end developer tasked with a React project for the first time, the library has the potential to make you question everything you've ever known.

Building with React requires a different kind of mindset. The freedom it allows means you're not propped up by structure or architecture. There's no fallback of an entire framework to keep you out of spaghetti code trouble.

So what does thinking in React look like? Here are four concepts that should help you think clearer when it comes to creating your next React component.

Start with single responsibility components

The one thing about React that often hits non-React developers is the need to drill down your UI into components. It is a process of abstracting your UI into little lego-like parts.

But the question then becomes – how small do these components need to be? The easiest way to determine this is to apply a single responsibility rule. What this means is that a component should only do one thing. Any time a component grows larger than a single responsibility, it should be refactored and decomposed into a collection of smaller components.

While this is easy to theorize, how can we implement it in real life?

One efficient method is to match your component to the data you're given via JSON. This is because your dynamic app is most likely connected to a data source in some form.

Let's take a look at the data and mockups below.

Here is the JSON from your backend developer:

const CART = [
  {category: 'Vegetables', price: '$2.99', unit: 'single item', stocked: true, name: 'Lettuce'},
  {category: 'Vegetables', price: '$1.99', unit: 'kg', stocked: true, name: 'Carrots'},
  {category: 'Breads', price: '$4.99', unit: 'bag', stocked: true, name: 'Premium Burger Buns'},
  {category: 'Meat', price: '$12.99', unit: 'kg', stocked: true, name: 'Mince'},
  {category: 'Spreads', price: '$3.99', unit: 'single item', stocked: true, name: 'Mayonnaise'},
    {category: 'Spreads', price: '$13.99', unit: 'single item', stocked: false, name: 'Premium Sauce'}]

Here is the UI from your designer:

If we break it down, the above data and UI can be summarized as below:

  • A filterable product table that contains
    • A search bar
    • A product table that contains
      • A product category
      • Corresponding product rows

Here's what it looks like when you circle the UI with the above components:


Each "component" captures a single responsibility and represents a hierarchy relationship between each component. The Product Category and Product Row can be seen as children to the Product Table. The Product Table is a child to the Filterable Product Table.

For React, decomposing your UI down to its smallest component doesn't mean you need every individual piece of data as its own component. This is a common mistake for new React developers because there's a misunderstanding on how atomic your components need to be. Applying single responsibility to components lets us evaluate the degree of decomposition on a set of elements.

Start with the static version

When building your UI, it can be tempting to code each individual component as separate parts and put them all together. This can be a logistic issue, especially on the CSS front, when it comes to getting things to sit in the right places for different view ratios.

This is why it's good to start with a static version that renders the entire view first. A static version just consumes the data and presents it on the screen. It doesn't matter in which order you begin constructing your UI. Your main focus here is to fit all the pieces together at the visual level.

For smaller projects and UIs, it's easier to go from the top of the hierarchy. For larger projects, it's easier to work from the bottom of the hierarchy and move your way up and out. A bottom-up approach is also easier to write tests against as you build your UI.

When you focus on the static version, you're not distracted by state management and the task of coordinating the building of each component out of context.

Minimum representation of states

This concept is an idea that's not often talked about when we learn React. What most of us encounter is that we need to represent our UI state in some form. There is no emphasis on a minimum representation.

But what is a minimum representation of state?

It is when a developer is able to capture wholly the minimum required states for your entire application. This means that you're not repeating yourself in another component. If you find yourself typing the same code (or something similar), it means that you are creating duplicates and not applying DRY on your code. The idea of DRY is simple: Don't repeat yourself. And this is essentially what minimum representation of states is.

For example, in the UI example above, you might have a functionality that adds new items to the list. However, to apply the concept of minimum representation, you wouldn't keep a count of how many items you have. Rather, you'd use the count method to do the task.

When you apply minimum representation, it also means that you are not dealing with unnecessary states, especially when the data is readily available. You produce the information you need just as you need it rather than storing it as a separate variable.

But how can you tell if something is not a state? Here are some questions I've developed to help me figure out if something is a state or not.

  • Is it passed in from a parent via props?
  • Does it remain unchanged over time?
  • Can you compute it based on any other state or props in your component?

If the answer is yes to any one of these questions, then it's not a state. In the UI example above, the only two things that these situations do not apply to is the value that a user types into the search bar and the toggle.

These simple questions can keep your React app from ballooning up unnecessarily and keep your code focused on the tasks it’s supposed to be doing.

All states need a home, but where?

React uses one-way data flow down the hierarchy. This means that children can only consume the data and are unable to enact any changes. Figuring out where a state should live is a process of determining what component is the parent in the hierarchy.

This can be tricky at first. So how can you figure where a state should live?

Here are a few simple steps that you can follow:

  • Identify every component that renders something based on that state.
  • Find a common owner component or a single component that exists above all the components that need the state in the hierarchy – i.e. the parent. This is the component that should own the state.
  • If there is no component that makes sense for owning the state. Create a new component just for holding the state and keep it separate until a logical component comes into existence that sits above the common components.

In the UI example above, it can be tempting to put our states in the Search Bar component. However, the state is also shared to the Product Table. Product Table can be seen as a sibling rather than a child, so it becomes a common user with Search Bar. To make it accessible to both components, based on the steps above, you need to go up one level into the Filterable Product Table, which acts as the common owner of both the Product Table and the Search Bar.

Final thoughts

Thinking in React is a process of making everything that happens in your app happen explicitly. While this seems simple enough, the task of structuring this can entrap a new React developer.

The thing with React is that there is no outline or enforced guideline to make you code a certain way. You can ignore all the suggestions above and your app will still work. However, methods of thinking as described in this piece can help structure your app for the long-term by giving it a foundation that conforms to a more logical, manageable, and scalable method of construction.

Discussion

Categories
Share Article

Continue Reading