7.1 More Hooks

# Refactor to Hooks

So far, we have discussed the React useState and useEffect hooks as well as the useParams, useLocation, and useHistory hooks.

React Hooks Reference (opens new window)

These are not the only built-in hooks for React. Here are a few more that you can use.

# useMemo

Let's you memoize a function's return value based on the parameters that are passed to it. Here is a short video about the concept of Memoization.

And here is a sample demonstration of the useMemo hook in action.

const memoizedValue = useMemo(() => {
  //call this function and remember the result
  computeExpensiveValue(a, b);
}, [a, b]);
//this is an array of dependencies to watch
//the dependencies are the values being passed into the function.
//use as many params as you need for your function.
//the returned value will be remembered as a result of that combination of params.
1
2
3
4
5
6
7
8

The useMemo hook runs during rendering. So, if you need to call a function with a side-effect then use the useEffect hook.

The purpose of this hook is to improve performance when a function is computationally expensive. Not to be used on all your functions.

# useContext

Now that you know what the Context API is, we can talk about the useContext hook.

Let's say that you have created a Context Object called MyContext with React.createContext().

const value = useContext(MyContext);
1

The useContext hook will search the component tree for the closest MyContext.Provider and return the value to our value variable.

When the Provider gets a new value, this hook will automatically update value and trigger any necessary re-renders.

# useReducer

The useReducer hook is an alternative to the useState hook. It is useful when you are using some type of state management system to update your state values. This is only necessary when you have complex state objects and want to control many different scenarios that could happen to your state values.

Here is a short video about the concept of a reducer.

And here is the signature of the useReducer hook. It accepts a reducer function that does something like this: (state, action) => newState. The useReducer hook will return an array with the current state object plus a method to call when you want to update your state object.

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

The initialArg is the initial value for your state object.

Here is an example that shows building a Counter Component and the reducer function knows that it is supposed to add or deduct one from the state.count property based on the value of the type property passed to the dispatch method.

const initialState = { count: 0 };

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    default:
      throw new Error();
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);
  return (
    <>
      Count: {state.count}
      <button onClick={() => dispatch({ type: 'decrement' })}>-</button>
      <button onClick={() => dispatch({ type: 'increment' })}>+</button>
    </>
  );
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# useCallback

The useCallback hook lets you create a memoized version of your callback function with dependencies.

const memoizedCallback = useCallback(
  () => {
    doSomething(a, b); //the function call that gets memoized
  },
  [a, b] //the dependencies mapped to the function
);
1
2
3
4
5
6

A new memoized version of the callback function is created if those dependencies change.

# useRef

This hook replaces the old createRef method used in your components.

import { useRef } from 'react';

function MyForm(props) {
  const inputEl = useRef(null);
  function clicked(ev) {
    inputEl.current.focus();
    //inputEl will hold a reference to the text input
    //the .current property will point to the DOM element
    //the ref={inputEl} in the JSX is what loads the ref
  }
  return (
    <>
      <input ref={inputEl} type="text" />
      <button onClick={clicked}>Focus the input</button>
    </>
  );
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# Custom Hooks

You can also create your own hooks to use in your application. Whenever you want to wrap some common functionality that deals with some asynchronous operation, you can create your own hook. Just be sure that you are following the rules of hooks.

  1. Start the name of your with use.
  2. Your Hook should be a wrapper function around one of the built-in ones that add additional functionality.
  3. Only call your hooks from the top level of your component, not inside a loop, condition, or nested function.
  4. Only call hooks from React Functions, not unrelated vanilla JavaScript functions. Hooks need the reference to your React Component.

This video explains how to use a couple of custom hooks. One with localStorage and a second with fetching from the Star Wars API.

# Lazy Loads and Code Splitting

As you can imagine, as your React SPA grows in size it means more and more content that has to be loaded as soon as your application is loaded. On a slow connection, that can be a huge amount of bandwidth.

Fear not though. React comes with a lazy method and a <Suspense> component that let us split our code into chunks that will only be loaded as the <Route> requires it.

# Review the Weather App

Now that we have talked more about the concepts of state and hooks. Let's go back and look at the React version of the Weather app that you built.

rlmckenney/mad9135-weather-demo (opens new window)

Last Updated: : 10/27/2021, 4:44:22 PM