Published on

React Basic Hooks Made Simple: What You Need to Know

React Hooks!πŸš€

Figure 1: React Hooks!πŸš€

What do you call a webhook in React? A React Hook of course! In simple terms, React Hook are ways that functional components use to attach themselves into the React Lifecyle and state system. The purpose of React Hooks are to provide functional components an alternative approach to maintaining state, as they are inherently stateless by default.

Before we get into React Hooks you might be asking: What is the React lifecycle? Well it is a series of changes in the React framework that consist of three phases: Mounting, Updating and Unmounting. Let's go through each phrase briefly:

Mounting

Mounting is the simple act of inserting React elements into the DOM(which stands for Document Object Model). Within this phase there are three notable methods that are called in the following sequentially order:

  1. constructor(): This method should be familiar to those coming from an object-oriented programming(OOP) background. This method is responsible for literally constructing the object by initializing a component's state and other initial values. Note that the constructor() method is only available for use in class based components and not functional components
  2. render(): This is the method that actually outputs the HTML onto the DOM
  3. componentDidMount(): This method is called after the component is rendered in the DOM. It is mainly used to run code that require the elements being present in the DOM

Updating

Updating is the second phase in the React lifecycle and it is primarily concerned with updating the component whenever a change in state or change in props is detected. Like with the mounting phase there are two notable methods that get called in this phase, those being:

  • shouldComponentUpdate(): This method is used to specify whether React should update the component's rendering. If the method returns true the component is updated, and the opposite goes for when false is returned. Here is a code snippet of this method:
class Navbar extends React.Component {

...

 shouldComponentUpdate() {
     return true; // this will cause the component to update
 }
...
}
  • componentDidUpdate(): This method is only called after the DOM is updated. Whenever a change to a component has been made after it has been rendered the update phase is triggered and executed. It is only after the update phase has finished that this method will be executed.

Note that components are available for updating right after they are mounted. As a practical example let's say a Car component has been mounted. It contains a state variable called carColor that was changed from red to white right after the component was finished mounting. Subsequently the update phase is triggered and the componentDidUpdate() method is called at the end. Here is a code snippet for the above example:

class Car extends React.component {

    constructor(){
        carColor = 'red';
    }

    componentDidMount(){
        this.carColor = 'white';
    }

    componentDidUpdate(){

        console.log("The car's color is " + carColor); // this will output 'The car's color is white'
    }

}

Unmounting

This is the simplest of the three phases because all it does is remove the component from the DOM. This is also refered to as unmounting in React.

There is only one important method for this phase, that being componentWillUnmount(). This method will be executed right before the component is about to be unmounted.

Examples of React Basic Hooks

Now let's look at some examples of React hooks in functional components:

State Hook

import React, { Component, useState, useEffect } from 'react';
export default function Login() {

  const [email, setEmail] = useState(() =>
    window.localStorage.getItem('hooksEmail') || ''
  );
  const [password, setPassword] = useState(() =>
    window.localStorage.getItem('hooksPassword') || ''
  );
  const handleEmailChange = (e) => setEmail(e.target.value);
  const handlePasswordChange = (e) => setPassword(e.target.value);

  useEffect(() => {
    window.localStorage.setItem('hooksEmail', email);
    window.localStorage.setItem('hooksPassword', password);
  });

  return (
    <div>
      <input value={email} onChange={handleEmailChange} /><br />
      <input value={password} onChange={handlePasswordChange} />
      <p>
        Logged in as: <span>{email}</span>
      </p>
    </div>
  );
}

The main Hook demonstrated in this example is the State Hook: useState(). It declares state variables and can be thought of as an alternative approach to using this.state as seen in class based components. It takes an initial value as an argument, so an expression such as this one: const firstName = useState(''); would assign an empty string as the value for the firstName state variable.

Effect Hook

The Effect Hook is basically a way to run React side-effects while preserving a certain degree of independence from the component's rendering cycle. In other works, the Effect Hook allows side effects to run separately from the rendering of the component. Confused? Don't worry, we will go over a code example soon.

But first, what is a React side-effect I heard you ask? Well its essentially any code that affects something outside the scope of a given functional component that would be run. Examples of side effects include initializing GraphQL Subscriptions, making API requests, manually inserting and deleting React elements from the DOM, just to name a few.

Ok so here's the examples demonstrating the Effect Hook:

import React, { useState, useEffect } from 'react';
import axios from 'axios';

function CarList() {
  const [carList, setCarList] = useState({ allCars: [] });

  useEffect(async () => {
    const result = await axios(
      'https://getMostFamousCars.com/api/v1/cars?numberOfCars=20',
    );

    setCarList(result.data);
  }, []);

  return (
    <ul>
      {carList.allCars.map(item => (
        <li key={item.vinNumber}>
          <a href={item.carPostUrl}>{item.carName}</a>
        </li>
      ))}
    </ul>
  );
}

Usually, the useEffect Hook will get executed on every render-cycle of the component, depending on the values passed into the second argument, but this example is a special scenario. In this case, the empty array passed in as the second argument signals React to only execute the Effect Hook once, which will be right after the component's first rendering.

Now let's see an example where the Effect Hook's second argument does contain a value:

function Bike(){
    const [price, setPrice] = useState(0);

    useEffect(() => {
        console.log("This bike's price is " + price);

    }, [price]));

}

In this case, the callback passed in as the first argument will be executed only when the value of the state variable price has changed. In extend this example further, if we can add as many variables into that array in the second argument as we want. After that, whenever any of those variables change value the callback passed in as the first argument will be executed.

Context Hook

The useContext() Hook can be though of as a way for React components to access React Context. It requires a React.createContext object as its primary parameter and returns the current context value assigned to that context object.

Let's briefly talk about React Context. This is a object that allows the passing of data through the component tree without having to use props. They are designed to overcome the complications that can arise from having to pass data from parent to child components, as done traditionally(which is calling 'prop drilling', more on this here). In short, React Context is a way to manage state and props globally.

Context objects can share data on a global level instead of having to traverse the component tree, as data passed into props is confined to.

Let's see an example usage of Context objects in action:

// based on CodeSandbox link: https://codesandbox.io/s/react-codesandbox-je6cc?file=/src/index.js
// src/run-context.js

import * as React from "react";

const RunContext = React.createContext();

function countReducer(state, action) {
  switch (action.type) {
    case "increment": {
      return { count: state.count + 1 };
    }
    case "decrement": {
      return { count: state.count - 1 };
    }
    default: {
      throw new Error(`Unhandled action type: ${action.type}`);
    }
  }
}

function RunProvider({ children }) {
  const [state, dispatch] = React.useReducer(countReducer, { count: 0 });
  // NOTE: you *might* need to memoize this value
  // Learn more in http://kcd.im/optimize-context
  const value = { state, dispatch };
  return <RunContext.Provider value={value}>{children}</RunContext.Provider>;
}

function useCount() {
  const context = React.useContext(RunContext);
  if (context === undefined) {
    throw new Error("useCount must be used within a CountProvider");
  }
  return context;
}

export { RunProvider, useCount };

As you see above, we create a RunContext object using the React.createContext() method. Then we create a RunProvider() method, which is a Provider object. This Provider is important because it allows consumer components to subscribe to context changes that happen anywhere in the component tree. Here is another code snippet that is needed to run our example app:



// based on CodeSandbox link: https://codesandbox.io/s/react-codesandbox-je6cc?file=/src/index.js
// src/count.js

import * as React from "react";
import { useCount } from "./run-context";

function RunDisplay() {
  const {
    state: { count }
  } = useCount();
  return <div>{`You ran  ${count} times this month`}</div>;
}

function Counter() {
  const { dispatch } = useCount();
  return (
    <button onClick={() => dispatch({ type: "increment" })}>
      Log your run
    </button>
  );
}

export { RunDisplay, Counter };

So the RunDisplay component is a component that will be consuming the runContext Context using the useCount() method defined in the previous code snippet. Additional, a Counter component will publish changes to all subscribers(in this case: RunDisplay component) whenever a click event is register for the <button> element that it is rendering. Finally here is a code snippet for the index.js entry point file:

// based on CodeSandbox link: https://codesandbox.io/s/react-codesandbox-je6cc?file=/src/index.js
// src/index.js

import * as React from "react";
import ReactDOM from "react-dom";
import { RunDisplay, Counter } from "./count";
import { RunProvider } from "./run-context";

function App() {
  return (
    <RunProvider>
      <RunDisplay />
      <Counter />
    </RunProvider>
  );
}

ReactDOM.render(<App />, document.getElementById("root"));

Note that in order to use Contexts we have to wrap our UI components(i.e RunDisplay component) in the RunProvider Context Provider class.

Here is the above code example in action!πŸš€

Figure 2: Here is the above code example in action!πŸš€

Here is the link to this CodeSandbox if you want to explore this example in greater detail.

Whew! Sorry for the long winded example on React Context but its important to make sure we understand this concept when explaining the useContext() Hook.

Now here is an example of useContext() in action:

// index.js
import { useState, createContext } from "react";
import ReactDOM from "react-dom";

export const ArmyContext = createContext()

First we have to create a Context using createContext(), as seen above.

// index.js

function MasterSergeant() {
  const [recruit, setRecruit] = useState("Jack Dempsey");

  return (
    <ArmyContext.Provider value={recruit}>
      <h1>{`Hello ${recruit}!`}</h1>  // This will render: "Hello Jack Dempsey"
      <Corporal recruit={recruit} />
    </ArmyContext.Provider>
  );
}

Then we have to wrap the child components in the Context Provider and supply the state value, as shown above. Doing so allows all components in the component tree to access the UserContext Context.

// main.js

import { useState, createContext, useContext } from "react";
import { ArmyContext } from "./index";

function Corporal() {
  return (
    <>
      <Private />
    </>
  );
}

function Private() {
  const recruit = useContext(ArmyContext);

  return (
    <>
      <h1>Component 5</h1>
      <h2>{`Hello ${recruit} again!`}</h2> // This will render: "Hello Jack Dempsey again!"
    </>
  );
}

Finally in a child component called Private, we call useContext() and use the ArmyContext to receive the value passed in through the ArmyContext.Provider in the MasterSergeant component.

Conclusion

Whew! If you made it this far, congrats! You have a dedication to learning that is sure to pay offπŸ‘

Although there are many more details about React Hooks that weren't covered in this post, for the sake of brevity letΒ us end it here. Hopefully you now have a better idea of what React Hooks are, along with why and how we use them.

Thanks for reading this blog post on React Basic Hooks!

If you have any questions or concerns please feel free to post a comment in this post and I will get back to you when I find the time.

If you found this article helpful please share it and make sure to follow me on Twitter and GitHub, connect with me on LinkedIn and subscribe to my YouTube channel.