Learning Use React Hooks

Note: This post is part 1 of three-parts Understanding react hooks post series. This learning post is still in active development and updated regularly.

React hooks were introduced in React 16.8 release. React Doc describes hooks as “functions that let you ‘hook into‘ React state and lifecycle features from function components. Hooks don’t work inside classes — they let you use React without classes.” In making sense of React, Dan Abramov writes “unlike patterns like render props or higher-order components, Hooks don’t introduce unnecessary nesting into your component tree. They also don’t suffer from the drawbacks of mixins”.

The main objective of this learning series is to understand the React Hooks, get started with an Overview of Hooks, then learn some basic use case examples and learn more deeply React context API.

Learning series
Part 1: React Hooks – An Overview (this post)
Part 2: Using UseStaticQuery Hook in a Gatsby Site
Part 3: Using React Context API in Gatsby site

The objective this part 1 of the React Hooks series is to get an overview of basic react hooks: useState(), useEffect() and useContext().

Prerequisite

To fully understand the React Hooks, it is essential to understand React classes and React State & lifecycle. In this learning series only an overview of React Hooks & its simple use in Gatsby site will be discussed.

Deep dive into React Classes, State & lifecycle will be discussed in separate learning note series.

React Hooks – An Overview

What are Hooks?

The React Doc describes Hooks “let you use state and other React features without writing a class”. This also allows to write customized Hooks to share reusable stateful logic between components.

The React hooks are regular functions that are imported directly from React library and can be used in React components. The React document lists a total 10 hooks of which following useState, useEffect and useContext are described as the most basic hooks.

The useState Hook

The useState hook is “similar to this.state in class component, except it doesn’t merge the old & new state together’. This can be inside a function to add local state to it.

The following Kingsley Silas example from the CSS-TRICKS post.

//source: https://css-tricks.com/intro-to-react-hooks/
class MyComponent extends React.component {
  constructor(props)
  super(props);
  this.state = {
    name: John Smith //  default state value    
  }
}

In the Class Component example above, a class is initialize with this.state (lines: 5-6).  The above example can be refactored using useState hook as shown below:

//source: https://css-tricks.com/intro-to-react-hooks/
import { useState } from 'react';
    
function MyComponent() {
 //define & call state variable
  const [name, setName] = useState('John Smith');
  
  return
    <div>
      <p>Hello!, {name}</p>
    </div>
}
// OUPUT
Hello! John smith

In this code example above, the useState hook is used outside of class and the state can be defined with an array containing two variables as (name) and call with (setName) inside a React component (line 6). The value of name variable is ‘John smith‘ where as setName is a function that can be used to update the value.

The default setName & setOtherName variables can be updated as described in this React Doc example using multiple state variables (below):

//src/app.js
import React, { useState } from 'react';

function App() {
  const [name, setName] = useState('Peter');
  const [otherName, setOtherName] = useState('Barney Stinson');

  return (
    <section className="main">
     <p>Hello, {name}!</p>
     <button onClick={() => setName('John Smith')}>
        Click me
      </button>
      <div>
      <p>Hello, {otherName}!</p>
      <button onClick={() => setOtherName('Sam Golberg')}>
        Click me
      </button>
      </div>
    </section>
  );
}
export default App;

In the example above first, useState hook was imported (line 2) which allows to use local state in functional component. Next, multiple state variables (name & setName) were defined inside App component with a default value of ‘Peter’  and ‘Berney Stinson’ (lines: 5-6). The name state is the property and setName (a function) which holds the state of the onClick element (an updated value). Likewise, the otherName and setOtherName state hold the default value of state (John smith) & updated value as ‘Sam Golberg’.  As React doc describes,  when the button is clicked, the setName or setOtherName function is called then React re-renders passing the updated values (lines: 11 & 16).

Screenshot of OUTPUT of name & setName attributes (left) and updated otherName & setOtherName attributes value after click me (right).
The useEffect Hook

The operations like API calls, data fetching, changing the DOM in React component are described as “side effects” (or “effects”). According to the React DocumentuseEffect serves the same purpose as componentDidMount, componentDidUpdate, and componentWillUnmount in React classes, but unified into a single API.”

The difference between the setState() and the useEffect() is that the later runs after render.

The following example from Hussein Almadi‘s article React Hooks: How to use useEffect() using two state (objects) name and familyName. Initial state would be “name” and “family” and after rendering the component it should be changed to something else.

// Source: Hussein Almadi's article
// File: src/app.js
import React, {useEffect, useState} from 'react';

export const App = () => {
  //State
  const [fullName, setFullName] = useState({name: 'name', familyName: 'family'});
  const [title, setTitle] = useState('Using useEffect() Hooks');

  //useEffect
  useEffect(() => {
     //console.log('useEffect has been called!');
     setFullName({name:'John',familyName: 'Smith'});
   },[]); //Pass Array as second argument

   return(
     <section className="main">
        <h1>Title: {title}</h1>
        <h5>Name: {fullName.name}</h5>
        <h5>Family Name: {fullName.familyName}</h5>
     </section>
    );
};

export default App;

In the example above, just like the previous useState hook example, both the useEffect() and useState() can be imported together from react (line 2).

First, states are defines (line: 7-8). Next, useEffect() function was defined with setFullName argument, this functions just like componentDidUpdate in class-based components. The useEffect() call only implemented when the second argument (eg. setFullName) gets changed (line 13). Because, a value of “John ” and “Smith” was passed to the setFullName (second argument) its value changed and useEffect() (see output screenshot below).

Just like in componerntDidMount which is called based on conditional statements, to use useEffect() function similarly we need to pass an empty array [] (line 14).

Figure: Screenshot of App component output which uses useEffect hook to update changed value.
Fetching Data useEffect() Hook

The Hussein Ahmadi’s article uses another simple example case useEffect() hook to fetch data from an external API like Axios. The following code snippets from Ahmadi’s article:

// code source: Hussein Ahmadi's article
import React, {useEffect, useState} from 'react';
import axios from 'axios';

export const CountryList = () => {
  const [countries, setCountries] = useState([]);
  const [load, setLoad] = useState(false);
  const [error, setError] = useState('');
    
  useEffect(() => {
     axios.get('https://restcountries.eu/rest/v2/all')
        .then(res => {
           setCountries(res.data);
           setLoad(true);
         })
        .catch(err => {
           setError(err.message);
           setLoad(true)
        })
  }, []);
    
   
  if (load) {
     return (<ul>
       {error ? <li>{error.message}</li> 
          : countries.map((country, index) => 
          <li key={index}>{country.name}</li>)}
       </ul>);
    } else {
       return (
         <div>
            Loading...
         </div>
     );
    }
};

In the example above from Hussein Ahmadi’s article uses three variables (lines: 6-8):  Countries (to list of our country names), Load (to show a loading text until our fetch process completes; it is to avoid async/await TypeErrors) and Error (to show error returns from our fetch method instead of the country list).  An an empty array as second argument is passed (line: 20) so that useEffect functions like componentDidMount. The screen output is shown below:

Screenshot (portion) of the output. Source: Ahmadi’s article.

Tip: If axios is already not installed, it should be installed as described in this document & should be used as described in this Git Hub example.

The useContext Hook

To understand useContext hook, a basic understanding of React Context is essential, which will be discussed in another post separately.

Definition

According the React Doc the “Context provides a way to pass data through the component tree without having to pass props down manually at every level.”

The React Context API allows to store a state value and access the value down in the tree, without drilling down with props. The React Documentation describes it “useContext lets you subscribe to React context without introducing nesting as shown below:

// code source React Doc
function Example() {
  const locale = useContext(LocaleContext);
  const theme = useContext(ThemeContext);
  // ...
}

The UseContext API consists of three main parts:

  • React.createContext which is passed the initial value. This returns an object with a Provider and a Consumer. The context value is determined  by the value prop from the nearest provider above.
  • The Provider component is used higher in the component hierarchy and accepts a prop called value (which can be anything).
  • The Consumer component is used anywhere below the provider in the component hierarchy and accepts a prop called “children” which must be a function that accepts the value and must return a react element (JSX).
  • The argument to useContext must be the context object itself.

The following example from the React Blog illustrates use of context API to inject a “theme”:

// example from React Blog
const ThemeContext = React.createContext('light');
class ThemeProvider extends React.Component {
  state = {theme: 'light'};

  render() {
    return (
      <ThemeContext.Provider value={this.state.theme}>   
        {this.props.children}      
      </ThemeContext.Provider>    );
  }
}

class ThemedButton extends React.Component {
  render() {
    return (
      <ThemeContext.Consumer>        
        {theme => <Button theme={theme} />}      
      </ThemeContext.Consumer>    );
  }
}

Explanation & additional use cases will described in part 3 of this learning series. Additional Information: Context API and use case examples

Wrapping Up

In this learning post series an an overview of three basic react hooks: useState(), useEffect() and useContext() was described with some basic use case examples. More detailed descriptions rationale of hooks in React will be described in a separate learning post series.

Next Post: Using UseStaticQuery Hook in a Gatsby Site

Useful Resources

While preparing this post, I have referred the following references extensively. Please refer to original posts for more detailed information.