Methods Of Improving And Optimizing Performance In React Apps

Methods Of Improving And Optimizing Performance In React Apps

Methods Of Improving And Optimizing Performance In React Apps

Shedrack Akintayo

React enables web applications to update their user interfaces (UIs) quickly, but that does not mean your medium or large React application will perform efficiently. Its performance will depend on how you use React when building it, and on your understanding of how React operates and the process through which components live through the various phases of their lifecycle. React offers a lot of performance improvements to a web app, and you can achieve these improvements through various techniques, features, and tools.

In this tutorial, we will discuss various methods of optimizing performance in React applications, and also the features of React that we can use to improve performance.

Where To Start Optimizing Performance In A React Application?

We can’t begin to optimize an app without knowing exactly when and where to optimize. You might be asking, “Where do we start?”

During the initial rendering process, React builds a DOM tree of components. So, when data changes in the DOM tree, we want React to re-render only those components that were affected by the change, skipping the other components in the tree that were not affected.

However, React could end up re-rendering all components in the DOM tree, even though not all are affected. This will result in longer loading time, wasted time, and even wasted CPU resources. We need to prevent this from happening. So, this is where we will focus our optimization effort.

In this situation, we could configure every component to only render or diff when necessary, to avoid wasting resources and time.

Measuring Performance

Never start the optimization process of your React application based on what you feel. Instead, use the measurement tools available to analyze the performance of your React app and get a detailed report of what might be slowing it down.

Analyzing React Components With Chrome’s Performance Tab

According to React’s documentation,, while you’re still in development mode, you can use the “Performance” tab in the Chrome browser to visualize how React components mount, update, and unmount. For example, the image below shows Chrome’s “Performance” tab profiling and analyzing my blog in development mode.

Performance profiler summary
Performance profiler summary (Large preview)

To do this, follow these steps:

  1. Disable all extensions temporarily, especially React Developer Tools, because they can mess with the result of the analysis. You can easily disable extensions by running your browser in incognito mode.
  2. Make sure the application is running in development mode. That is, the application should be running on your localhost.
  3. Open Chrome’s Developer Tools, click on the “Performance” tab, and then click the “Record” button.
  4. Perform the actions you want to profile. Don’t record more than 20 seconds, or else Chrome might hang.
  5. Stop the recording.
  6. React events will be grouped under the “User Timing” label.

The numbers from the profiler are relative. Most times and components will render more quickly in production. Nevertheless, this should help you to figure out when the UI is updated by mistake, as well as how deep and how often the UI updates occur.

React Developer Tools Profiler

According to React’s documentation, in react-dom 16.5+ and react-native 0.57+, enhanced profiling capabilities are available in developer mode using React Developer Tools Profiler. The profiler uses React’s experimental Profiler API to collate timing information about each component that’s rendered, in order to identify performance bottlenecks in a React application.

Just download React Developer Tools for your browser, and then you can use the profiler tool that ships with it. The profiler can only be used either in development mode or in the production-profiling build of React v16.5+. The image below is the profiler summary of my blog in development mode using React Developer Tools Profiler:

React Developer Tools Profiler flamegraph
React Developer Tools Profiler flamegraph (Large preview)

To achieve this, follow these steps:

  1. Download React Developer Tools.
  2. Make sure your React application is either in development mode or in the production-profiling build of React v16.5+.
  3. Open Chrome’s “Developer Tools” tab. A new tab named “Profiler” will be available, provided by React Developer Tools.
  4. Click the “Record” button, and perform the actions you want to profile. Ideally, stop recording after you have performed the actions you want to profile.
  5. A graph (known as a flamegraph) will appear with all of the event handlers and components of your React app.

Note: See the documentation for more information.

Memoization With React.memo()

React v16 was released with an additional API, a higher-order component called React.memo(). According to the documentation, this exists only as a performance optimization.

Its name, “memo” comes from memoization, which is basically a form of optimization used mainly to speed up code by storing the results of expensive function calls and returning the stored result whenever the same expensive function is called again.

Memoization is a technique for executing a function once, usually a pure function, and then saving the result in memory. If we try to execute that function again, with the same arguments as before, it will just return the previously saved result from the first function’s execution, without executing the function again.

Mapping the description above to the React ecosystem, the functions mentioned are React components and the arguments are props.

The default behavior of a component declared using React.memo() is that it renders only if the props in the component have changed. It does a shallow comparison of the props to check this, but an option is available to override this.

React.memo() boosts the performance of a React app by avoiding re-rendering components whose props haven’t changed or when re-rendering is not needed.

The code below is the basic syntax of React.memo():

const MemoizedComponent = React.memeo((props) => {
// Component code goes in here
})

When To Use React.memo()

  • Pure functional component
    You can use React.memo() if your component is functional, is given the same props, and always renders the same output. You can also use React.memo() on non-pure-functional components with React hooks.
  • The component renders often
    You can use React.memo() to wrap a component that renders often.
  • The component re-renders with same props
    Use React.memo() to wrap a component that is usually provided with the same props during re-rendering.
  • Medium to high elements
    Use it for a component that contains a medium to high number of UI elements to check props for equality.

Note: Be careful when memoizing components that make use of props as callbacks. Be sure to use the same callback function instance between renderings. This is because the parent component could provide different instances of the callback function on every render, which will cause the memoization process to break. To fix this, make sure that the memoized component always receives the same callback instance.

Let’s see how we can use memoization in a real-world situation. The functional component below, called “Photo”, uses React.memo() to prevent re-rendering.

export function Photo({ title, views }) {
  return (
    <div>
      <div>Photo title: {title}</div>
      <div>Location: {location}</div>
    </div>
  );
}
// memoize the component
export const MemoizedPhoto = React.memo(Photo);

The code above consists of a functional component that displays a div containing a photo title and the location of the subject in the photo. We are also memoizing the component by creating a new function and calling it MemoizedPhoto. Memoizing the photo component will prevent the component from re-rendering as long as the props, title, and location are the same on subsequent renderings.

// On first render, React calls MemoizedPhoto function.
<MemoizedPhoto
  title="Effiel Tower"
  location="Paris"
/>

// On next render, React does not call MemoizedPhoto function,
// preventing rendering
<MemoizedPhoto
  title="Effiel Tower"
  location="Paris"
/>

Here, React calls the memoized function only once. It won’t render the component in the next call as long as the props remain the same.

Bundling And Minification

In React single-page applications, we can bundle and minify all our JavaScript code into a single file. This is OK, as long as our application is relatively small.

As our React application grows, bundling and minifying all of our JavaScript code into a single file becomes problematic, difficult to understand, and tedious. It will also affect the performance and loading time of our React app because we are sending a large JavaScript file to the browser. So, we need some process to help us split the code base into various files and deliver them to the browser in intervals as needed.

In a situation like this, we can use some form of asset bundler like Webpack, and then leverage its code-splitting functionality to split our application into multiple files.

Code-splitting is suggested in Webpack’s documentation as a means to improve the loading time of an application. It is also suggested in React’s documentation for lazy-loading (serving only the things currently needed by the user), which can dramatically improve performance.

Webpack suggests three general approaches to code-splitting:

  • Entry points
    Manually split code using entry configuration.
  • Duplication prevention
    Use SplitChunksPlugin to de-duplicate and split chunks.
  • Dynamic imports
    Split code via inline function calls within modules.

Benefits Of Code Splitting

  • Splitting code assists with the browser’s cache resources and with code that doesn’t change often.
  • It also helps the browser to download resources in parallel, which reduces the overall loading time of the application.
  • It enables us to split code into chunks that will be loaded on demand or as needed by the application.
  • It keeps the initial downloading of resources on first render relatively small, thereby reducing the loading time of the app.
Bundling and minification process
Bundling and minification process (Large preview)

Immutable Data Structures

React’s documentation talks of the power of not mutating data. Any data that cannot be changed is immutable. Immutability is a concept that React programmers should understand.

An immutable value or object cannot be changed. So, when there is an update, a new value is created in memory, leaving the old one untouched.

We can use immutable data structures and React.PureComponent to automatically check for a complex state change. For example, if the state in your application is immutable, you can actually save all state objects in a single store with a state-management library like Redux, enabling you to easily implement undo and redo functionality.

Don’t forget that we cannot change immutable data once it’s created.

Benefits Of Immutable Data Structures

  • They have no side effects.
  • Immutable data objects are easy to create, test, and use.
  • They help us to write logic that can be used to quickly check for updates in state, without having to check the data over and over again.
  • They help to prevent temporal coupling (a type of coupling in which code depends on the order of execution).

The following libraries help to provide a set of immutable data structures:

  • immutability-helper
    Mutate a copy of data without changing the source.
  • Immutable.js
    Immutable persistent data collections for JavaScript increase efficiency and simplicity.
  • seamless-immutable
    Immutable data structures for JavaScript become backwards-compatible with normal JavaScript arrays and objects.
  • React-copy-write
    This gives immutable state with a mutable API.

Other Methods Of Improving Performance

Use A Production Build Before Deployment

React’s documentation suggests using the minified production build when deploying your app.

React Developer Tools’ “production build” warning
React Developer Tools’ “production build” warning (Large preview)

Avoid Anonymous Functions

Because anonymous functions aren’t assigned an identifier (via const/let/var), they aren’t persistent whenever a component inevitably gets rendered again. This causes JavaScript to allocate new memory each time this component is re-rendered, instead of allocating a single piece of memory only once, like when named functions are being used.

import React from 'react';

// Don’t do this.
class Dont extends Component {
  render() {
    return (
      <button onClick={() => console.log('Do not do this')}>
        Don’t
      </button>
    );
  }
}

// The better way
class Do extends Component {
  handleClick = () => {
    console.log('This is OK');
  }
  render() {
    return (
      <button onClick={this.handleClick}>
        Do
      </button>
    );
  }
}

The code above shows two different ways to make a button perform an action on click. The first code block uses an anonymous function in the onClick() prop, and this would affect performance. The second code block uses a named function in the onClick() function, which is the correct way in this scenario.

Mounting And Unmounting Components Often Is Expensive

Using conditionals or tenaries to make a component disappear (i.e. to unmount it) is not advisable, because the component made to disappear will cause the browser to repaint and reflow. This is an expensive process because the positions and geometries of HTML elements in the document will have to be recalculated. Instead, we can use CSS’ opacity and visibility properties to hide the component. This way, the component will still be in the DOM but invisible, without any performance cost.

Virtualize Long Lists

The documentation suggests that if you are rendering a list with a large amount of data, you should render a small portion of the data in the list at a time within the visible viewport. Then, you can render more data as the list is being scrolled; hence, the data is displayed only when it is in the viewport. This process is called “windowing”. In windowing, a small subset of rows are rendered at any given time. There are popular libraries for doing this, two of which are maintained by Brian Vaughn:

Conclusion

There are several other methods of improving the performance of your React application. This article has discussed the most important and effective methods of performance optimization.

I hope you’ve enjoyed reading through this tutorial. You can learn more via the resources listed below. If you have any questions, leave them in the comments section below. I’ll be happy to answer every one of them.

Smashing Editorial (ks, ra, al, il)

Styling Components In React

Styling Components In React

Styling Components In React

Shedrack Akintayo

Styling React components over the years has improved and become much easier with various techniques and strategies. In this tutorial, we’re going to learn how to style React components using four major styling strategies — with examples on how to use them. In the process, I will explain the cons and pros of these styling strategies, and by the end of this tutorial, you’ll know all about styling React components and how they work along with the various methods that can be used for styling these components.

Note: A basic understanding of ReactJS and CSS would be good to have for this tutorial.

What Does ‘Styling’ In React Applications Even Mean?

The reason you’ll style your React application is no different from that which you have in mind when styling other websites or web applications you have been working on. Styling in React applications describes how React components or elements are displayed on screen or any other media.

The whole essence of building frontend UIs with React is how flexible it is to build these UIs especially as components and also style them to give us a great look and experience. It is important to know that whatever styling strategy you may decide to use is still CSS — you are writing CSS like you’ve always done. The difference is that the strategies (which we’ll be looking at) help make the process easy because of the uniqueness of React.

Major Styling Strategies In React

There are various strategies to follow when planning to style React components, these strategies have also increased and evolved over the years. In this tutorial, we would be talking about the most popular and modern styling strategies, and how to use them to style our React components. These styling strategies include:

  1. CSS and SCSS Stylesheets
    This involves using separate stylesheets like our conventional way of styling our HTML websites either with CSS or a CSS preprocessor called SASS.
  2. CSS Modules
    A CSS Module is a CSS file in which all class names and animation names are scoped locally by default.
  3. styled-components
    styled-components is a library for React and React Native that allows you to use component-level styles in your application that are written with a mixture of JavaScript and CSS using a technique called CSS-in-JS.
  4. JSS
    JSS is an authoring tool for CSS which allows you to use JavaScript to describe styles in a declarative, conflict-free and reusable way. It can compile in the browser, server-side or at build time in Node.

In the next section of this tutorial, we are going to be talking about each of these strategies of styling with examples of their syntax.

1. CSS And SASS Stylesheets

CSS or SCSS Stylesheets is a styling strategy that involves the use of external CSS or SASS stylesheets that can be imported into your React components depending on where you need the styling to be applied.

For example, we have a SASS file of styles called Box.scss we need to use in a component called Box.js, below is the code for our SASS file.

// Box.scss
.Box {
  margin: 40px;
  border: 5px black;
}

.Box_content {
  font-size: 16px;
  text-align: center;
}

In other to make use of this styling inside our Box component all we need to do is import the SASS file directly into our Box.js component like so:

import React from 'react';
import './Box.css';

const Box = () => (
  <div className="Box">
    <p className="Box_content"> Styling React Components </p>
  </div>
);

export default Box;

After creating the styles and importing it into Box.js file, we can then set the className attribute to the match what we have in the stylesheet.

While using this strategy, you could also leverage on existing frameworks like; Bulma, Bootstrap, etc. These frameworks provide you with existing classes and components you could plug into your React application without styling every aspect of your application.

Benefits of using CSS and SASS Stylesheets

  1. It is much more popular than the rest of the styling strategies, so there is a ton of helpful resources when you run into a bug.
  2. Caching & Performance
    Standard CSS files are easy for the browser to optimize for, caching the files locally for repeat visits, and ultimately giving performance wins.
  3. Un-opinionated and Universal
    CSS and SASS is universal and has no opinion on how you render your UI making it a great choice for teams that have legacy CSS and are migrating over to a new framework or rebuilding their website or product.
  4. Quickly Iterate A New Design
    You can very easily rip out the entire stylesheet and create a new one to refresh the look and feel of your app without digging through potentially hundreds of components.
  5. CSS Frameworks
    CSS frameworks come in handy if you are a new developer, or you want to quickly work on a prototype without diving deep into writing your own full-blown stylesheets. CSS frameworks will provide you with building blocks to get your idea off the ground. Some of these frameworks include, Bootstrap, Bulma, Semantic UI, Materialize.

Shortcomings of using CSS and SASS Stylesheets

  1. Readability
    If not properly structured, a CSS or SASS stylesheet can become long and difficult to navigate through as the application becomes complex.
  2. Legacy CSS Can Live On For Years
    Most times these really large stylesheets can become so complex and long that cleaning up old, outdated or even unused styles can be a pain.
Note: “Sass has two syntaxes. The most commonly used syntax is known as “SCSS” (for “Sassy CSS”) and is a superset of CSS syntax. This means that every valid CSS stylesheet is valid SCSS as well. SCSS files use the extension .scss.
The second, older syntax is known as the indented syntax (or just “.sass”). Inspired by Haml’s terseness, it’s intended for people who prefer conciseness over similarity to CSS. Instead of brackets and semicolons, it uses the indentation of lines to specify blocks. Files in the indented syntax use the extension .sass.”

CSS Modules

A CSS Module is a CSS file in which all class names and animation names are scoped locally by default. When using CSS Modules, each React component is provided with its own CSS file, that is scoped to that file and component alone.

The beauty of CSS modules happens at build time when the local class names which can be super simple without conflict are mapped directly to the automatically-generated ones and are exported as a JS object literal to use within React.

We can make use of CSS Modules in our React applications by importing the file directly into the component file.

For example, the code below is an example of how to use a CSS module in a React Component.

//Box.css
 :local(.container) {
   margin: 40px;
   border: 5px dashed pink;
 }
 :local(.content) {
   font-size: 15px;
   text-align: center;
 }

:local(.className) is used when you use create-react-app boilerplate because of webpack configurations.

When using webpack, you can add the loader and also include the module to your webpack.config.js in other to make CSS modules work with Webpack.

test: /\.css$/,
loader: 'style!css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]' 
}

In other to make use of this CSS Module inside our Box component we need to import the module file directly into our Box.js component and use the className instead of style prop to access the style like so:

import React from 'react';
import styles from './Box.css';

const Box = () => (
  <div className={styles.container}>
    <p className={styles.content}> Styling React Components </p>
  </div>
);

export default Box;

styles here is an object that contains the styles we created in Box.css. This object will contain the classes; container and content that maps to their respective styles. To make use of them, we assign the element’s className to the appropriate class we have in Box.css.

Benefits Of Using CSS Modules

  1. Modular and reusable CSS,
  2. No more styling conflicts,
  3. Explicit dependencies,
  4. Local scope,
  5. Clear dependencies,
  6. No Code duplication in case of SSR,
  7. No Additional costs in JS payload,
  8. Variables, Sharing variables in CSS and exposing it to JavaScript.

Shortcomings of using CSS Modules

  1. Extra build tools (e.g. webpack).
  2. Mixing CSS Modules and global CSS classes is cumbersome.
  3. When a Reference is made to an undefined CSS Module, it resolves to undefined without a warning.
  4. Using the styles object whenever constructing a className is compulsory.
  5. Only allows usage of camelCase CSS class names.

styled-components

styled-components is a library for React and React Native that allows you to use component-level styles in your application that are written with a mixture of JavaScript and CSS.

It was created with the same method of operation of CSS Modules, a way to write CSS that’s scoped to a single component, and not accessible to any other element in the page or even component.

styled-components allows React developers to write plain CSS in React components without having to worry about clashing of class names.

For example, if we need to implement styling in our Box.js file using styled components, we would first need to carry out the following steps:

  • First, we need to install styled-components library by running npm install styled-components --save.
  • We then need to import the styled component library into our component by writing import styled from 'styled-components';.
  • Now we can create a variable by selecting a particular HTML element where we store our style keys.
  • Then we use the name of our variable we created as a wrapper around our JSX elements.

The code below is an implementation of all the steps we mentioned above.

import React from 'react';
import styled from 'styled-components';

const Box = styled.div`
  margin: 40px;
  border: 5px black;
`;

const Content = styled.p`
  font-size: 16px;
  text-align: center;
`;

const Box = () => (
  <Box>
    <Content> Styling React Components </Content>
  </Box>
);

export default Box;

In the code above, we import the styled object from styled-components, which makes use of tagged template literals to style your component. We then create a variable that would hold our styling and also act as a wrapper around content, that’s why we have the <Box> and <Content> tags, in this variables, we assign it to the styled object plus the HTML element we want to style then followed by the accompanying styles for the HTML element. To use the variables we created for styling all we need to do is wrap our JSX or content in between them as tags.

Benefits Of Using styled-components

  1. Consistency
    styled-components make it easy for you to publish a React component to NPM. These components can be customised through props and/or extending via styled(Component) and no clashing with CSS selectors.
  2. Sass Syntax Out-Of-The-Box
    You can get SASS trademark syntax out of the box without having to install or setup SASS or any extra build tool.
  3. Dynamic Styling
    You can make use of props to dynamically change the styles in any way that feels natural to anyone comfortable with React.
  4. Theming
    Using React’s Context API, styled-components offers a ThemeContext that can you can pass a theme object directly to, making it very accessible in any of your components, and by default can be interpolated into your styled definitions.

Shortcomings Of Using styled-components

  1. Learning Curve
    Frontend developers that are already comfortable with writing traditional CSS will have to learn a different way of styling that is different from how traditional CSS is written.
  2. Integration with Legacy CSS can be painful.
    If you’re making use of a UI library like Material UI or even traditional CSS, integrating styled-components together with them can be confusing to locate and debug styles.
  3. Performance
    styled-components converts all of the style definitions in your React component into plain CSS at build time and the inject everything into the <style> tags in the head of your index.html file. This affects performance in the sense that it is not only increasing the size of our HTML file which can have an impact on the load time, but there is also no way to chunk the output CSS either.

JSS

JSS is an authoring tool for CSS which allows you to use JavaScript to describe styles in a declarative, conflict-free and reusable way. It can compile in the browser, server-side or at build time in Node. JSS is a new styling strategy that hasn’t been adapted so much. It is framework agnostic and consists of multiple packages: the core, plugins, framework integrations and others.

JSS has third party API adapters that can be used to write JSS like styles but differently, these third party API adapters include:

  • Styled-JSS
    This is a styled-component API adapter.
  • Glamor-JSS
    Glamor flavored CSS with JSS under the hood.
  • Aphrodite-JSS
    Aphrodite like API.

React-JSS

React-JSS makes use of JSS with React using the new Hooks API. JSS and the default preset are already built into the library. According to the official React-JSS docs, the following are the benefits of using React-JSS instead of the core JSS library in your React components.

  • Dynamic Theming
    This allows context-based theme propagation and runtime updates.
  • Critical CSS Extraction
    The only CSS from rendered components gets extracted.
  • Lazy Evaluation
    Style Sheets are created when a component mounts and removed when it’s unmounted.
  • The static part of a Style Sheet will be shared between all elements.
  • Function values and rules are updated automatically with any data you pass to useStyles(data). You can pass props, state or anything from context for example.

The code below is an example of how React-JSS is used.

import React from 'react'
import {render} from 'react-dom'
import injectSheet, { ThemeProvider } from 'react-jss'
const styles = (theme) => ({
  wrapper: {
    padding: 40,
    background: theme.background,
    textAlign: 'center'
  },
  title: {
    font: {
      size: 40,
      weight: 900,
    },
    color: props => props.color
  },
  link: {
    color: theme.color,
    '&:hover': {
      opacity: 0.5
    }
  }
})
const Comp = ({ classes }) => (
  <div className={classes.wrapper}>
    <h1 className={classes.title}>Hello React-JSS!</h1>
    <a
      className={classes.link}
      href="http://cssinjs.org/react-jss"
      traget="_blank"
    >
      See docs
    </a>
  </div>
)
const StyledComp = injectSheet(styles)(Comp)
const theme = {
  background: '#aaa',
  color: '#24292e'
}
const App = () => (
  <ThemeProvider theme={theme}>
    <StyledComp color="red"/>
  </ThemeProvider>
)
render(<App />, document.getElementById("root"))

In the code above, which somewhat similar to using styled components, we import injectSheet and ThemeProvider from the react-jss library. The ThemeProvider is a High-Order component in React, which passes the theme object down the React tree by the use of context. It will contain the root theme of the component. While injectSheet is used for injecting the stylesheet we have created in this case styles into the main component.

const Comp = ({ classes }) => (
  <div className={classes.wrapper}>
    <h1 className={classes.title}>Hello React-JSS!</h1>
    <a
      className={classes.link}
      href="http://cssinjs.org/react-jss"
      traget="_blank"
    >
      See docs
    </a>
  </div>
)

The code above is the main React component that has not been injected with the styles object we have created, it contains the main code for our React component and it is going to be styled when we inject it with the styles object that we have created.

const StyledComp = injectSheet(styles)(Comp)

The line of code above is injecting the styles we have created into the component we created it for using the injectSheet() function.

const theme = {
  background: '#aaa',
  color: '#24292e'
}

The code above holds the theme object that would be passed to the <ThemeProvider> HOC via context and it acts as the root theme of our component.

const App = () => (
  <ThemeProvider theme={theme}>
    <StyledComp color="red"/>
  </ThemeProvider>
)

In this portion of the code, what we are doing here is using the <ThemeProvider> HOC, we are rendering our component that we have injected the styled sheet we created into <StyledComp color= "red"/>.

At the end of rendering, this is what will be displayed on your bro.

Code Output.
Code Output. (Large preview)

Benefits Of JSS

  1. Local Scoping
    JSS supports local scoping, taking it to the next level by automating scoping, which leads to a high level of predictability.
  2. Encapsulation
    Encapsulation facilitates maintenance and eliminates errors, as you can modify all component-related code and style in the same place, without having to worry about unexpectedly changing other parts of the application.
  3. Reusability
    Components are reusable, so you only have to write them once, then you can run them everywhere while maintaining their styling too.
  4. Dynamic Styling
    You can make use of props to dynamically change the styles in any way that feels natural to anyone comfortable with React.

Shortcomings Of JSS

  1. Learning Curve
    Learning JSS can be very tricky especially frontend developers that are already used to writing traditional CSS.
  2. Extra Layer of Complexity
    Putting a CSS-in-JS library into use adds an extra layer to your React application, which can sometimes be unnecessary.
  3. Code Readability
    Custom or Automatically generated selectors can be very difficult to read especially when using your browser devtools to debug.

Conclusion

Each of these has its advantages and disadvantages, and it all depends on your personal/company preference and the complexity of your application. Also, whatever styling strategy you may decide to use, it is still basically CSS. You can write CSS like you’ve always done, but React and other libraries offer solutions that can also help with styling.

I hope you enjoyed working through this tutorial. You could always read more on Styling React Components from the references below. If you have any questions, leave a comment below and I’ll be happy to reply to each and every single one.

Resources

Smashing Editorial (ks, ra, yk, il)

Getting Started With The React Hooks API

Getting Started With The React Hooks API

Getting Started With The React Hooks API

Shedrack Akintayo

When React 16.8 was released officially in early February 2019, it shipped with an additional API that lets you use state and other features in React without writing a class. This additional API is called Hooks and they’re becoming popular in the React ecosystem, from open-sourced projects to being used in production applications.

React Hooks are completely opt-in which means that rewriting existing code is unecessary, they do not contain any breaking changes, and they’re available for use with the release of React 16.8. Some curious developers have been making use of the Hooks API even before it was released officially, but back then it was not stable and was only an experimental feature. Now it is stable and recommended for React developers to use.

Note: We won’t be talking about React or JavaScript in general. A good knowledge of ReactJS and JavaScript will come in handy as you work through this tutorial.

What Are React Hooks?

React Hooks are in-built functions that allow React developers to use state and lifecycle methods inside functional components, they also work together with existing code, so they can easily be adopted into a codebase. The way Hooks were pitched to the public was that they allow developers to use state in functional components but under the hood, Hooks are much more powerful than that. They allow React Developers to enjoy the following benefits:

  • Improved code reuse;
  • Better code composition;
  • Better defaults;
  • Sharing non-visual logic with the use of custom hooks;
  • Flexibility in moving up and down the components tree.

With React Hooks, developers get the power to use functional components for almost everything they need to do from just rendering UI to also handling state and also logic — which is pretty neat.

Motivation Behind The Release Of React Hooks

According to the ReactJS official documentation, the following are the motivation behind the release of React Hooks:

  • Reusing stateful logic between components is difficult.
    With Hooks, you can reuse logic between your components without changing their architecture or structure.
  • Complex components can be difficult to understand.
    When components become larger and carry out many operations, it becomes difficult to understand in the long run. Hooks solve this by allowing you separate a particular single component into various smaller functions based upon what pieces of this separated component are related (such as setting up a subscription or fetching data), rather than having to force a split based on lifecycle methods.
  • Classes are quite confusing.
    Classes are a hindrance to learning React properly; you would need to understand how this in JavaScript works which differs from other languages. React Hooks solves this problem by allowing developers to use the best of React features without having to use classes.

The Rules Of Hooks

There are two main rules that are strictly to be adhered to as stated by the React core team in which they outlined in the hooks proposal documentation.

  • Make sure to not use Hooks inside loops, conditions, or nested functions;
  • Only use Hooks from inside React Functions.

Basic React Hooks

There are 10 in-built hooks that was shipped with React 16.8 but the basic (commonly used) hooks include:

These are the 4 basic hooks that are commonly used by React developers that have adopted React Hooks into their codebases.

useState()

The useState() hook allows React developers to update, handle and manipulate state inside functional components without needing to convert it to a class component. Let’s use the code snippet below is a simple Age counter component and we will use it to explain the power and syntax of the useState() hook.

function App() {
  const [age, setAge] = useState(19);
  const handleClick = () => setAge(age + 1)

  return 
      <div> 
          I am {age} Years Old 
        <div> 
        <button onClick={handleClick}>Increase my age! </button>
      </div>
   </div>
}

If you’ve noticed, our component looks pretty simple, concise and it’s now a functional component and also does not have the level of complexity that a class component would have.

The useState() hook receives an initial state as an argument and then returns, by making use of array destructuring in JavaScript, the two variables in the array can be named what. The first variable is the actual state, while the second variable is a function that is meant for updating the state by providing a new state.

Our finished React app (Large preview)

This is how our component should look when it is rendered in our React application. By clicking on the “Increase my Age” button, the state of the age will change and the component would work just like a class component with state.

useEffect()

The useEffect() hook accepts a function that would contain effectual code. In functional components, effects like mutations, subscriptions, timers, logging, and other effects are not allowed to be placed inside a functional component because doing so would lead to a lot of inconsistencies when the UI is rendered and also confusing bugs.

In using the useEffect() hook, the effectual function passed into it will execute right after the render has been displayed on the screen. Effects are basically peeked into the imperative way of building UIs that is quite different from React’s functional way.

By default, effects are executed mainly after the render has been completed, but you have the option to also fire them when certain values change.

The useEffect() hook mostly into play for side-effects that are usually used for interactions with the Browser/DOM API or external API-like data fetching or subscriptions. Also, if you are already familiar with how React lifecycle methods work, you can also think of useEffect() hook as component mounting, updating and unmounting — all combined in one function. It lets us replicate the lifecycle methods in functional components.

We will use the code snippets below to explain the most basic way that we can by using the useEffect() hook.

Step 1: Define The State Of Your Application
import React, {useState} from 'react';
function App() {
    //Define State
    const [name, setName] = useState({firstName: 'name', surname: 'surname'});
    const [title, setTitle] = useState('BIO');
    
    return(
        <div>
            <h1>Title: {title}</h1>
            <h3>Name: {name.firstName}</h3>
            <h3>Surname: {name.surname}</h3>
        </div>
    );
};
export default App

Just like we discussed in the previous section on how to use the useState() hook to handle state inside functional components, we used it in our code snippet to set the state for our app that renders my full name.

Step 2: Call The useEffect Hook
import React, {useState, useEffect} from 'react';
function App() {
    //Define State
    const [name, setName] = useState({firstName: 'name', surname: 'surname'});
    const [title, setTitle] = useState('BIO');
   
    //Call the use effect hook
    useEffect(() => {
      setName({name: 'Shedrack', surname: 'Akintayo'})
    }, [])//pass in an empty array as a second argument
    
    return(
        <div>
            <h1>Title: {title}</h1>
            <h3>Name: {name.firstName}</h3>
            <h3>Surname: {name.surame}</h3>
        </div>
    );
};
export default App

We have now imported the useEffect hook and also made use of the useEffect() function to set the state of our the name and surname property which is pretty neat and concise.

You may have noticed the useEffect hook in the second argument which is an empty array; this is because it contains a call to the setFullName which does not have a list of dependencies. Passing the second argument will prevent an infinite chain of updates (componentDidUpdate()) and it’ll also allow our useEffect() hook to act as a componentDidMount lifecycle method and render once without re-rendering on every change in the tree.

Our React app should now look like this:

React app using the useEffect Hook (Large preview)

We can also use change the title property of our application inside the useEffect() function by calling the setTitle() function, like so:

import React, {useState, useEffect} from 'react';
function App() {
    //Define State
    const [name, setName] = useState({firstName: 'name', surname: 'surname'});
    const [title, setTitle] = useState('BIO');
   
    //Call the use effect hook
    useEffect(() => {
      setName({name: 'Shedrack', surname: 'Akintayo'})
      setTitle({'My Full Name'}) //Set Title
    }, [])// pass in an empty array as a second argument
    
    return(
        <div>
            <h1>Title: {title}</h1>
            <h3>Name: {name.firstName}</h3>
            <h3>Surname: {name.surame}</h3>
        </div>
    );
};
export default App

Now after our application has rerendered, it now shows the new title.

Our finished project (Large preview)

useContext()

The useContext() hook accepts a context object, i.e the value that is returned from React.createContext, and then it returns the current context value for that context.

This hook gives functional components easy access to your React app context. Before the useContext hook was introduced you would need to set up a contextType or a <Consumer> to access your global state passed down from some provider in a class component.

Basically, the useContext hook works with the React Context API which is a way to share data deeply throughout your app without the need to manually pass your app props down through various levels. Now, the useContext() makes using Context a little easier.

The code snippets below will show how the Context API works and how the useContext Hook makes it better.

The Normal Way To Use The Context API
import React from "react";
import ReactDOM from "react-dom";

const NumberContext = React.createContext();
function App() {
  return (
    <NumberContext.Provider value={45}>
      <div>
        <Display />
      </div>
    </NumberContext.Provider>
  );
}
function Display() {
  return (
    <NumberContext.Consumer>
      {value => <div>The answer to the question is {value}.</div>}
    </NumberContext.Consumer>
  );
}
ReactDOM.render(<App />, document.querySelector("#root"));

Let’s now break down the code snippet and explain each concept.

Below, we are creating a context called NumberContext. It is meant to return an object with two values: { Provider, Consumer }.

const NumberContext = React.createContext();

Then we use the Provider value that was returned from the NumberContext we created to make a particular value available to all the children.

function App() {
  return (
    <NumberContext.Provider value={45}>
      <div>
        <Display />
      </div>
    </NumberContext.Provider>
  );
}

With that, we can use the Consumer value that was returned from the NumberContext we created to get the value we made available to all children. If you have noticed, this component did not get any props.

function Display() {
  return (
    <NumberContext.Consumer>
      {value => <div>The answer to the question is {value}.</div>}
    </NumberContext.Consumer>
  );
}
ReactDOM.render(<App />, document.querySelector("#root"));

Note how we were able to get the value from the App component into the Display component by wrapping our content in a NumberContext.Consumer and using the render props method to retrieve the value and render it.

Everything works well and the render props method we used is a really good pattern for handling dynamic data, but in the long run, it does introduce some unnecessary nesting and confusion if you’re not used to it.

Using The useContext Method

To explain the useContext method we will rewrite the Display component using the useContext hook.

// import useContext (or we could write React.useContext)
import React, { useContext } from 'react';

// old code goes here

function Display() {
  const value = useContext(NumberContext);
  return <div>The answer is {value}.</div>;
}

That’s all we need to do in order to display our value. Pretty neat, right? You call the useContext() hook and pass in the context object we created and we grab the value from it.

Note: Don’t forget that the argument that is passed to the useContext hook must be the context object itself and any component calling the useContext will always re-render when the context value changes.

useReducer()

The useReducer hook is used for handling complex states and transitions in state. It takes in a reducer function and also an initial state input; then, it returns the current state and also a dispatch function as output by the means of array destructuring.

The code below is the proper syntax for using the useReducer hook.

const [state, dispatch] = useReducer(reducer, initialArg, init);

It is sort of an alternative to the useState hook; it is usually preferable to useState when you have complex state logic that has to do with multiple sub-values or when the next state is dependent on the previous one.

Other React Hooks Available

useCallback This hook returns a callback function that is memoized and that only changes if one dependency in the dependency tree changes.
useMemo This hook returns a memoized value, you can pass in a “create” function and also an array of dependencies. The value it returns will only use the memoized value again if one of the dependencies in the dependency tree changes.
useRef This hook returns a mutable ref object whose .current property is initialized to the passed argument (initialValue). The returned object will be available for the full lifetime of the component.
useImperativeHandle This hook is used for customizing the instance value that is made available for parent components when using refs in React.
useLayoutEffect This hook similar to the useEffect hook, however, it fires synchronously after all DOM mutations. It also renders in the same way as componentDidUpdate and componentDidMount.
useDebugValue This hook can be used to display a label for custom hooks in the React Dev Tools. It is very useful for debugging with the React Dev Tools.

Custom React Hooks

A “custom Hook” is a JavaScript function whose names are prefixed with the word use and can be used to call other Hooks. It also lets you to extract component logic into reusable functions; they are normal JavaScript functions that can make use of other Hooks inside of it, and also contain a common stateful logic that can be made use of within multiple components.

The code snippets below demonstrate an example of a custom React Hook for implementing infinite scroll (by Paulo Levy):

import { useState } from "react";

export const useInfiniteScroll = (start = 30, pace = 10) => {
  const [limit, setLimit] = useState(start);
  window.onscroll = () => {
    if (
      window.innerHeight + document.documentElement.scrollTop ===
      document.documentElement.offsetHeight
    ) {
      setLimit(limit + pace);
    }
  };
  return limit;
};

This custom Hook accepts two arguments which are start and pace. The start argument is the starting number of elements to be rendered while the pace argument is the subsequent number of elements that are to be rendered. By default, the start and pace arguments are set to 30 and 10 respectively which means you can actually call the Hook without any arguments and those default values will be used instead.

So in order to use this Hook within a React app, we would use it with an online API that returns ‘fake’ data:

import React, { useState, useEffect } from "react";
import { useInfiniteScroll } from "./useInfiniteScroll";

const App = () => {
  let infiniteScroll = useInfiniteScroll();

  const [tableContent, setTableContent] = useState([]);

  useEffect(() => {
    fetch("https://jsonplaceholder.typicode.com/todos/")
      .then(response => response.json())
      .then(json => setTableContent(json));
  }, []);

  return (
    <div style={{ textAlign: "center" }}>
      <table>
        <thead>
          <tr>
            <th>User ID</th>
            <th>Title</th>
          </tr>
        </thead>
        <tbody>
          {tableContent.slice(0, infiniteScroll).map(content => {
            return (
              <tr key={content.id}>
                <td style={{ paddingTop: "10px" }}>{content.userId}</td>
                <td style={{ paddingTop: "10px" }}>{content.title}</td>
              </tr>
            );
          })}
        </tbody>
      </table>
    </div>
  );
};

export default App;

The code above will render a list of fake data (userID and title) that make use of the infinite scroll hook to display the initial number of data on the screen.

Conclusion

I hope you enjoyed working through this tutorial. You could always read more on React Hooks from the references below.

If you have any questions, you can leave them in the comments section and I’ll be happy to answer every single one!

The supporting repo for this article is available on Github.

Resources And Further Reading

Smashing Editorial (ks, ra, yk, il)