Building UI’s the react way

Lasal Hettiarachchi
7 min readApr 23, 2021

Ever see the facebook page reloading when you add a new comment or your instagram feed going away when u double tap on that cat video that your friend posted? Thats react working its magic under the hood.

React is an open source JavaScript based UI library used to build responsive interfaces . Unlike other front end technologies , react orchestrates the front end as a single page application meaning that page does not have to reload whenever a component element changes . React can compare the DOM with a virtual DOM and run its reconciliation algorithm to figure out what was changed and re-render only the changed component to the DOM instead of refreshing .

React structures the UI elements as a reusable structure called a component. Starting from ES6, react has provided 2 ways of creating a component.

  1. By extending the React.Component class (As a class component)
  2. As a functional component

Each approach has its pros and cons , but class components are more versatile and has more functionality built into it. Both class components and functional components can have states (By useState hook in functional component) and can pass props from parent component to child component. In this article , we will discuss how to properly breakdown the UI elements into components and how to use state and props properly.

Assume the following scenario of a super center which sells various kinds of products. Here the user can see the price of different goods based on the category. Users are also able to search items that are only available.

[
{category: "Sporting Goods", price: "$49.99", stocked: true, name: "Football"},
{category: "Sporting Goods", price: "$9.99", stocked: true, name: "Baseball"},
{category: "Sporting Goods", price: "$29.99", stocked: false, name: "Basketball"},
{category: "Electronics", price: "$99.99", stocked: true, name: "iPod Touch"},
{category: "Electronics", price: "$399.99", stocked: false, name: "iPhone 5"},
{category: "Electronics", price: "$199.99", stocked: true, name: "Nexus 7"}
];

Assume that the json object that is passed to the front end takes the above form. Analyzing the above object and the requirement , Let us try to formulate a react UI breaking the elements into coponents.

If we observe the above UI carefully , we can see a pattern repeating where under a category , several goods are rendered. We can break down these repeating patterns into components and pass props down from parent in order to render the needed child elements. Similarly we can observe a repeating pattern of categories within the product table itself. So we can break down that into a separate component and similarly pass props. Both the above mentioned components together forms a separate reusable structure as a product table . Contrarily , the search box and the checkbox serves different functionality. So it can be broken down to a separate component. Both the product table and the search component merges together to form the Filterable product table itself which can be another re useable UI element. Based on the above analysis , the UI can be broken down into components following the given rational.

  1. FilterableProductTable (orange): contains the entirety of the example
  2. SearchBar (blue): receives all user input
  3. ProductTable (green): displays and filters the data collection based on user input
  4. ProductCategoryRow (turquoise): displays a heading for each category
  5. ProductRow (red): displays a row for each product

A component in its essence should only serve one responsibility and should be easily understandable. If we take our above example , the ProductRow component only takes care of the of the responsibility of returning one product. The SearchBar only takes care of the searching functionality.

Based on the above structuring , the implementation can be done as follows

class ProductCategoryRow extends React.Component {
render() {
const category = this.props.category;
return (
<tr>
<th colSpan="2">
{category}
</th>
</tr>
);
}
}

class ProductRow extends React.Component {
render() {
const product = this.props.product;
const name = product.stocked ?
product.name :
<span style={{color: 'red'}}>
{product.name}
</span>;

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

class ProductTable extends React.Component {
render() {
const filterText = this.props.filterText;
const inStockOnly = this.props.inStockOnly;

const rows = [];
let lastCategory = null;

this.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;
});

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

class SearchBar extends React.Component {
constructor(props) {
super(props);
this.handleFilterTextChange = this.handleFilterTextChange.bind(this);
this.handleInStockChange = this.handleInStockChange.bind(this);
}

handleFilterTextChange(e) {
this.props.onFilterTextChange(e.target.value);
}

handleInStockChange(e) {
this.props.onInStockChange(e.target.checked);
}

render() {
return (
<form>
<input
type="text"
placeholder="Search..."
value={this.props.filterText}
onChange={this.handleFilterTextChange}
/>
<p>
<input
type="checkbox"
checked={this.props.inStockOnly}
onChange={this.handleInStockChange}
/>
{' '}
Only show products in stock
</p>
</form>
);
}
}

class FilterableProductTable extends React.Component {
constructor(props) {
super(props);
this.state = {
filterText: '',
inStockOnly: false
};

this.handleFilterTextChange = this.handleFilterTextChange.bind(this);
this.handleInStockChange = this.handleInStockChange.bind(this);
}

handleFilterTextChange(filterText) {
this.setState({
filterText: filterText
});
}

handleInStockChange(inStockOnly) {
this.setState({
inStockOnly: inStockOnly
})
}

render() {
return (
<div>
<SearchBar
filterText={this.state.filterText}
inStockOnly={this.state.inStockOnly}
onFilterTextChange={this.handleFilterTextChange}
onInStockChange={this.handleInStockChange}
/>
<ProductTable
products={this.props.products}
filterText={this.state.filterText}
inStockOnly={this.state.inStockOnly}
/>
</div>
);
}
}


const PRODUCTS = [
{category: 'Sporting Goods', price: '$49.99', stocked: true, name: 'Football'},
{category: 'Sporting Goods', price: '$9.99', stocked: true, name: 'Baseball'},
{category: 'Sporting Goods', price: '$29.99', stocked: false, name: 'Basketball'},
{category: 'Electronics', price: '$99.99', stocked: true, name: 'iPod Touch'},
{category: 'Electronics', price: '$399.99', stocked: false, name: 'iPhone 5'},
{category: 'Electronics', price: '$199.99', stocked: true, name: 'Nexus 7'}
];

ReactDOM.render(
<FilterableProductTable products={PRODUCTS} />,
document.getElementById('container')
);

Let us now try to reason why this was implemented as above. But before diving into the nuances of the implementation , let us try to understand what class components, state and props are. For this let us use the FilterableProductTable component

class FilterableProductTable extends React.Component {
constructor(props) {
super(props);
this.state = {
filterText: '',
inStockOnly: false
};

this.handleFilterTextChange = this.handleFilterTextChange.bind(this);
this.handleInStockChange = this.handleInStockChange.bind(this);
}

handleFilterTextChange(filterText) {
this.setState({
filterText: filterText
});
}

handleInStockChange(inStockOnly) {
this.setState({
inStockOnly: inStockOnly
})
}

render() {
return (
<div>
<SearchBar
filterText={this.state.filterText}
inStockOnly={this.state.inStockOnly}
onFilterTextChange={this.handleFilterTextChange}
onInStockChange={this.handleInStockChange}
/>
<ProductTable
products={this.props.products}
filterText={this.state.filterText}
inStockOnly={this.state.inStockOnly}
/>
</div>
);
}
}

As the name suggests , a class component serves the purpose of a class which can have attributes and methods. Attributes are kept by the means of state . When extending the React.Component , a method called render() has to be implemented that returns the JSX or the components to be rendered into the DOM. Class components also have a constructor where we can initialize state. Other than that there are several other methods such as componentDidMount(), componentWillMount(), componentDidUpdate() and several other react life cycle methods where the power in react really lies. (But for the purpose of this article , we will not dive into them).

So what is state? State is an object attribute values related to the component is stored. whenever the state of a component is changed , the component is re-rendered. As mentioned in above , we can initialize state in the constructor of a class component and changed either through it or through one of its child components . As a rule of thumbs, an attribute is not a state if,

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

So what is props? Props are arguments that can be passed down from parent components to the child component. React only allows one way communication . In the above example , we can see that ,

<ProductTable
products={this.props.products}
filterText={this.state.filterText}
inStockOnly={this.state.inStockOnly}
/>

This is rendering the Product table by passing products , filterText, isStockOnly as props from the FilterableProductTable component.

Now that we have a basic understanding on how react works , let us try to understand the above code.

FilterableProduct , ProductRow ,ProductTable , SearchBar, FilterableProductTable , are all class components. Products is an array used to mimic a json object passed to the front end.

The requirement is to update the UI based on what is in the searchbar (textbox, checkbox) and render only the relevant goods based on those inputs in the productTable component. So in order to achieve this attributes from Searchbar has to be passed to the productTable. How can this be achieved?. We can see that a state called filterText and isOnlyStock is kept in the FilterableProductTable component which wraps both the ProductTable component and the SearchBar component and passed down to both the components as props. But why are we creating the state in the FilterableProductTable component rather than in the SearchBar component. Afterall, we get the inputs in that component? React only allows one way data flow and that is through props. If filterText and isOnlyStock state was kept in the searchbar component , there is no way to pass that state into the productTable which is its sibling component. That is why state is kept in the wrapper component and passed down to the searchbar to be updated and to the product table to do the relevant rendering.

This approach is the best way to properly keep the state in react

Code resource — https://reactjs.org/docs/thinking-in-react.html

--

--