Thinking in React

Ranjul Arumadi
Last Updated: May 13, 2022

Introduction

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

 

Want to know about UI frameworks that run on Javascript? Read this blog Best JavaScript UI FrameWork To Use In 2021 


Here are five concepts that should help you think clearer when creating your next React component.

Thinking in React step by step

Step 1: Break UI Into Components

First, draw boxes around every component and subcomponent in the mock-up and give them all names. If we have a designer, they may have already done it for us. Mostly their photoshop name will be the names of React Components.

 

To know what its components should be,  we use the Single Responsibility Principle Technique. It means a component should only do one thing. Anytime a component grows larger than that, it should be decomposed into smaller components.

 

We generally will be working with JSON data, so separate the UI into components where each component matches one piece of our data model.

 

The below picture shows the mock-up broken down into five components:
 

UI mock-up

 

  • FilterableProductTable:- it wraps the entire app.
  • Search Bar:- receives user input.
  • ProductTable:- displays and filters data based on user input
  • ProductCategoryRow:- displays the heading for each category
  • ProductRow:- shows a row for each product.

 

As we have identified the react components, let's arrange them into a hierarchy:-

  •  FilterableProductTable
    • SearchBar
    • ProductTable
      • ProductCategoryRow
      • ProductRow

Step 2: Build A Static Version

Now we have a react component hierarchy, we can write some code. One of the many easy ways to get started is to build a version that renders the data in UI but has no interactivity. We can build top-down or bottom-up. This means we can start from the top of the hierarchy, i.e., FilterableProductTable, work our way down, or from the bottom of the hierarchy, i.e., ProductRow and work our way to the top.
 

We will start from the bottom, i.e., ProductRow.
 

Code: 

function ProductRow(props) {
  const product = props.product;
  const name = product.stocked; 
    product.name :
    // When stock is not available set color of text to red
    <span style={{color: 'red'}}>
      {product.name}
    </span>;

  return (
    <tr>
      <td>{name}</td>
      <td>{product.price}</td>
    </tr>
  );
}

 

Here we create a functional component ProductRow which will be passed props. The props will include the product and its data. In our mock-up, we have some names in red colour, this is because these products are not in stock, so we include a ternary operator for the name to see if we wanted to add custom styling for products not in stock. Finally, we return a table row with the product and its price.

 

Next, we built the ProductCategoryRow(props) function.

 

Code:

function ProductCategoryRow(props) {
  const category = props.category;
  return (
    <tr>
      <th colSpan="2">
        {category}
      </th>
    </tr>
  );
}

 

Here we will need a prop i.e., the category of the product. Then we return the table row with a category span of 2 columns.
 

Next, we built the ProductTable(props) component.
 

Code:

function ProductTable(props) {
  const rows = [];
  let lastCategory = null;

 
// Loop through each product that is passed from our props and to the product.
  props.products.forEach((product) => {
// If the product's category is not equal to the lastCategory, then we will add a new category row using our ProductCategoryRow component.
    if (product.category !== lastCategory) {
      rows.push(
        <ProductCategoryRow
          category={product.category}
          key={product.category} />
      );
    }
// We pass to that component the category and use the category as a key
    rows.push(
      <ProductRow
        product={product}
        key={product.name} />
    );
// Set the lastCategory to the current product's Category.

    lastCategory = product.category;
  });

 
// Return a table with the row.

 

  return (
    <table>
      <thead>
        <tr>
          <th>Name</th>
          <th>Price</th>
        </tr>
      </thead>
      <tbody>{rows}</tbody>
    </table>
  );

 

Next, we built the SearchBar() component.

 

Code:

function SearchBar() {
  return (
    <form>
      <input type="text" placeholder="Search..." />
      <p>
        <input type="checkbox" /> Only show products in stock
      </p>
    </form>
  );
}

 

This will return a form with a text input and checkbox input.
 

Next we built the FilteredProductTable(props) component.

 

Code:

function FilterableProductTable(props) {
  return (
    <div>
      <SearchBar />
      <ProductTable products={props.products} />
    </div>
  );
}

 

This will return the search bar and the product table components. We will also pass the products to the product table component.

 

Then we will render them to the DOM by passing our JSON data to the FilterableProductTable component.

 

Code:

const PRODUCTS = [
  {category: 'Drinks', price: '$0.5', stocked: true, name: 'Lime Juice'},
  {category: 'Drinks', price: '$0.8', stocked: true, name: 'Milk Shake'},
  {category: 'Drinks', price: '$0.6', stocked: false, name: 'Lassi'},
  {category: 'Snacks', price: '$1.47', stocked: true, name: 'Pav Bhaji'},
  {category: 'Snacks', price: '$0.8', stocked: false, name: 'Samosa'},
  {category: 'Snacks', price: '$1.0', stocked: true, name: 'Dahi Puri'}
];
 
ReactDOM.render(
  <FilterableProductTable products={PRODUCTS} />,
  document.getElementById('root')
);

 

After this, we will see a static representation of the app.

 

Output

Step 3: Identify the Minimal Representation of State

To build an app correctly, we need to identify the minimal complete representation of the UI state our app requires. This is a vital step when it comes to thinking in React.
 

For this, we use the "DRY" design principle, which means Don't Repeat Yourself, i.e., if we are typing the same things multiple times, then there must be a way to combine those.

 

Find out the minimal representation of the state that your application needs. After this find everything else that you need as required.  

 

For example, if you’re building a TODO list, keep an array of the TODO items around; don’t keep a separate state variable for the count. Instead, when you want to render the TODO count, take the length of the TODO items array.

 

Make a note of all the pieces of data that we have in our example application. We have:

  • The original products list
  • The search text the user has entered
  • The checkbox value
  • The list of products that are filtered

 

Let’s go through each and every one of them and find out which one is a state. To do this, we ask three questions about each piece of data. If you get a positive answer to any of these, it is probably not in the state. The questions are as follows:-

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

 

The reason it’s not in the state is that the original list of products is passed in as props. The search text and the checkbox are state since they change over time and can’t be computed from anything. The filtered list of products isn’t stated because it can be found out by combining the original product list with the search text entered by the user and value of the checkbox.

 

So finally, our state is:

  • The search text that the user has entered
  • The checkbox value, i.e. ticked or unticked

Step 4: Identify Where Your State Should Live?

Let’s identify which react components mutate or own our state. React uses one data flow down the component hierarchy., It may not be immediately clear which component should own what state. This can be challenging for beginners.

 

So follow these steps for each state of the application:-

  • Identify every React component that renders things based on that state.
  • Find a common owner component. This will be a single component that is above all the components that need the state in the hierarchy.
  • Either the common owner or another component higher up in the hierarchy should own the state.
  • If you are unable to find a react component where it makes sense to own the state, create a new react component just for holding the state and add it somewhere in the hierarchy above the common owner component.

 

Let’s run through this strategy for our application:

  • ProductTable needs to filter the product list based on state, and SearchBar requires to display the search text and checked state.
  • The common owner component is FilterableProductTable.
  • The filter text and checked value living in FilterableProductTable are justified.
     

Code:

function FilterableProductTable(props) {
  const [filterText, setFilterText] = React.useState(""); 
  const [inStockOnly, setInStockOnly] = React.useState(false);
  
  return (
    <div>
      <SearchBar 
        filterText={filterText}
        inStockOnly={inStockOnly}  
      />
      <ProductTable 
        products={props.products} 
        filterText={filterText}
        inStockOnly={inStockOnly} 
      />
    </div>
  );
}

 

Since now our state lives in FilterableProductTable, we will use the useState("") to create a filter text InStockOnly states. Then we will pass filterText and inStockOnly to the product table and search bar as props.

 

Code:

function ProductTable(props) {
  const filterText = props.filterText;
  const inStockOnly = props.inStockOnly;
  
  const rows = [];
  let lastCategory = null;

  props.products.forEach((product) => {
    if (product.name.indexOf(filterText) === -1) {
      return;
    }
    if (inStockOnly && !product.stocked) {
      return;
    }
    if (product.category !== lastCategory) {
      rows.push(
        <ProductCategoryRow
          category={product.category}
          key={product.category} />
      );
    }

rows.push(
      <ProductRow
        product={product}
        key={product.name} />
    );
    lastCategory = product.category;
  });

 

Finally, we will use these props to filter the rows in productTable and set the values of the font field in the search bar.

 

You can now see how your application will behave. Set filterText to “Samosa" and refresh your app. You will see that the data table is getting updated correctly.


Output

Step 5: Add Inverse Data Flow

So far, we’ve built an app that renders correctly as a function of props and state flowing down the hierarchy. Now it is time to support data flowing the other way. The form components deep in the hierarchy need to update the state in FilterableProductTable.

 

React makes this data flow explicit to help you understand how your program works. The downside to this method is that it does require a little more typing than traditional two-way data binding.

 

If you try to type or check the box in the previous version of the example (step 4), you will see that React ignores your input. This is intentional, as we’ve set the value prop of the input always to be equal to the state passed in from FilterableProductTable.

 

Code:

function SearchBar(props) {
  const filterText = props.filterText;
  const inStockOnly = props.inStockOnly;
  
  return (
    <form>
      <input 
        type="text" 
        placeholder="Search..." 
        value={filterText} 
      />
      <p>
        <input 
          type="checkbox" 
          checked={inStockOnly} 
        />
        {' '}
        Only show products in stock
      </p>
    </form>
  );
}

 

Let’s think about what we want to happen. We want to make sure that whenever the user changes the form, we update the state to reflect the user input. Since react components should only update their own state,
 

Code:

function FilterableProductTable(props) {
  const [filterText, setFilterText] = React.useState(""); 
  const [inStockOnly, setInStockOnly] = React.useState(false);
  
  return (
    <div>
      <SearchBar 
        filterText={filterText}
        inStockOnly={inStockOnly}  
      />
      <ProductTable 
        products={props.products} 
        filterText={filterText}
        inStockOnly={inStockOnly} 
      />
    </div>
  );
}

 

FilterableProductTable will pass callbacks to SearchBar that will fire whenever the state should be updated. We can use the onChange event on the inputs to be notified of it. The callbacks passed by FilterableProductTable will call setState(), and the app will be updated.

 

Output

 

That’s it!. This blog should give you a good idea of creating React projects by thinking in React.

Frequently Asked Questions

1. How can I easily break my UI into components?

Ans:- One method to easily break UI into components is to draw boxes around every component and subcomponent in the mockup and give them all names. This will simplify the work.
 

2. What are the advantages of using React?

Ans:- Some of the advantages of using React are Use of Virtual DOM to improve efficiency, SEO friendly, Huge ecosystem of libraries to choose from, easiness to learn, etc.

 

3. What is virtual DOM? How does react use the virtual DOM to render the UI?

Ans:- Virtual DOM is a concept where a virtual representation of the real DOM is kept inside the memory and is synced with the real DOM by a library such as ReactDOM.

Key Takeaways

Thinking in React is a process of thinking of making everything that happens in the app happen explicitly. Even if you do not follow the above steps, you still will get the result in the end. Still, it is better to think and do it in the way of React as mentioned above as it will help in the long-term manageability of the application.

 

Want to get better at thinking in React?, check out this course, Advanced Front End Web Development Course — React.js offered by Coding Ninjas, and learn to build interactive web pages!. Practice fifteen most frequently asked React JS interview questions here. Do more projects in React to get better with thinking in React and get proficient with the React library.

Was this article helpful ?
0 upvotes

Comments

No comments yet

Be the first to share what you think