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.
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);
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);
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>
</>
);
}
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
);
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>
</>
);
}
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.
- Start the name of your with
use
. - Your Hook should be a wrapper function around one of the built-in ones that add additional functionality.
- Only call your hooks from the top level of your component, not inside a loop, condition, or nested function.
- 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.