React Hooks - Some React Hooks Explained

Built-in React Hooks

Hooks are a new addition in React 16.8. They let you use state and other React features without writing a class. Tey are build-in in the chore of React.

One of the benefits of React is that it does for you, if you determine some sort of system to manage the state of the application

Changing the state of the application and as you change the state of the application the webpage itself re-renders automatically to show the new values.

List of Hooks

  1. State Hooks
    1. useState
    2. useReducer
  2. Effect Hooks
    1. useEffect
    2. useLayoutEffect
  3. Ref Hooks
    1. useRef
  4. Context Hooks
    1. useContext
  5. Performance Hooks
    1. useMemo
    2. useCallback
    3. useDeferredValue
  6. Other Hooks
    1. useDebugValue

State Hooks

To add state to a component, use one of these Hooks:

  • useState declares a state variable that you can update directly.

  • useReducer declares a state variable with the update logic inside a reducer function

useState

useState is a React Hook that lets you add a state variable to your component.

When data changes re-render de UI

An example of using useState

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// Reactive value, setter
const [state, setState] = useState(initialState);


// A function example
function UseStateEffect() {
const [data, setData] = useState("");
const [inputValue, setInputValue] = useState("");

let onChange = (event) => {
const newValue = event.target.value
setInputValue(newValue);
}

useEffect(() => {
getDummyData(async () => {
const { data} = await axios.get("https://jsonplaceholder.typicode.com/comments")
setData(response.data[0].email);
console.log("API WAS CALLED");
})
}, []);

return (
<div>
<input placeholder = "Enter something..." onChange={onChange} />
{inputValue}
{/* <h1>{data}</h1> */}
</div>
);
}

export default UseStateEffect;

useReducer

It’s an alternative to the useState, which form me is less cleaner and adding extra complexity. I wouldn't use Redux is more complex rather than use setState to manage the state when it grows.

Declares a state variable with the update logic inside a reducer function.

Call useReducer at the top level of your component to manage its state with a reducer.

An example of using useReduce

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// Similar to set state, but a different way to set/manage state using the REDUX pattern.
useReducer(reducer, initialArg, init?)

// An example
const reducer = (state, action) => {
switch (action.type) {
case "INCREMENT":
return { count: state.count + 1, showText: state.showText };
case "toggleShowText":
return { count: state.count, showText: !state.showText };
default:
return state;
}
};

const UseReducer = () => {
const [state, dispatch] = useReducer(reducer, { count: 0, showText: true });

return (
<div>
<h1>{state.count}</h1>
<button
onClick={() => {
dispatch({ type: "INCREMENT" });
dispatch({ type: "toggleShowText" });
}}
>
Click Here
</button>

{state.showText && <p>This is a text</p>}
</div>
);
};


Effect Hooks

Effects let a component connect to and synchronize with external systems. This includes dealing with network, browser DOM, animations, widgets written using a different UI library, and other non-React code.

  • useEffect connects a component to an external system.

Effects are an “escape hatch” from the React paradigm. Don’t use Effects to orchestrate the data flow of your application. If you’re not interacting with an external system, you might not need an Effect.

There are two rarely used variations of useEffect with differences in timing:

  • useLayoutEffect fires before the browser repaints the screen. You can measure layout here.
  • useInsertionEffect fires before React makes changes to the DOM. Libraries can insert dynamic CSS here.

useEffect

useEffect is a React Hook that lets you synchronize a component with an external system.

  useEffect(setup, dependencies?)

An example of using useEffect

Call useEffect at the top level of your component to declare an Effect:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import { useEffect } from 'react';
import { createConnection } from './chat.js';

function ChatRoom({ roomId }) {
// Reactive value, setter
const [serverUrl, setServerUrl] = useState('https://localhost:1234');

useEffect(
() => {
// RUN when mounted and when state changes (2).
// alert("Hello side effect!")
const connection = createConnection(serverUrl, roomId);
connection.connect();
// RUN before the component is removed from the DOM
return () => {
connection.disconnect();
};
},
// Array of dependencies, with [] there is no dependencies, it's triggered once.
// RUN when serverUrl or roomId change.
[serverUrl, roomId]
);
// ...
}

useLayoutEffect

Pitfall: useLayoutEffect can hurt performance. Prefer useEffect when possible

  • Similar to useEffect but
  • RUNS after render, but before pointing the script.
  • CAUTION blocks visual updates until your callback is finished.

useLayoutEffect is a version of useEffect that fires before the browser repaints the screen.

useLayoutEffect(setup, dependencies?)

An example of using useLayoutEffect

Call useLayoutEffect perform the layout measurements before the browser repaints the screen:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import React, { useState, useLayoutEffect, useRef } from 'react';

function MyComponent() {
const [width, setWidth] = useState(0);
const ref = useRef(null);

/* ***************************************************************
* Similar to useEffect, but
* RUNS after render, but before pointing the script.
* CAUTION blocks visual updates until your callback is finished
* *************************************************************** */

// Use useLayoutEffect to measure the width of the element
useLayoutEffect(() => {
if (ref.current) {
const newWidth = ref.current.getBoundingClientRect().width;
setWidth(newWidth);
}
}, []);

return (
<div ref={ref}>
This element has a width of {width}px.
</div>
);
}

Note that useLayoutEffect should be used sparingly, as it can negatively impact the performance of your application if used excessively or inefficiently. You should only use useLayoutEffect when you need to perform a measurement or layout calculation that affects the visual appearance of your application.

Ref Hooks

Refs let a component hold some information that isn’t used for rendering, like a DOM node or a timeout ID. Unlike with state, updating a ref does not re-render your component. Refs are an “escape hatch” from the React paradigm. They are useful when you need to work with non-React systems, such as the built-in browser APIs.

  • useRef declares a ref. You can hold any value in it, but most often it’s used to hold a DOM node.
  • useImperativeHandle lets you customize the ref exposed by your component. This is rarely used.

Easiest way to manipulate and access DOM elements.

useRef

useRef is a React Hook that lets you reference a value that’s not needed for rendering.

  const ref = useRef(initialValue)

An example of using useRef

Use the useRef hook in a React component to store a reference to a DOM element:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import React, { useRef } from 'react';

function MyComponent() {
const inputRef = useRef(null);

function handleButtonClick() {
// Focus the input element
inputRef.current.focus();
}

return (
<div>
<input type="text" placeholder="Example..." ref={inputRef} />
<button onClick={handleButtonClick}>Focus input</button>
</div>
);
}

By using the useRef hook to store a reference to the input element, we can avoid the need to rely on DOM queries or selectors to manipulate the input element, which can be slower and less reliable. Instead, we can directly access the input element using the current property of the inputRef object.

Creating a some short of to-do application, clear an input file when submitted the value


Context Hooks

Context lets a component receive information from distant parents without passing it as props. For example, your app’s top-level component can pass the current UI theme to all components below, no matter how deep.

useContext

To share value through disconnected components, we can create a context object.

useContext is a React Hook that lets you read and subscribe to context from your component.

  const value = useContext(SomeContext)

Examples of using useContext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import { createContext, useContext } from "react";

const moods = {
happy: "😄",
sad: "😒",
}

// To share value through disconnected components, we can create a context object.
// CONTEXT share data without passing props. during the entire component tree.
const MoodContext = createContext(moods)

function MoodEmoji() {
// Consume value from nearest parent provider.
const mood = useContext(MoodContext)

return <p>{ mood.happy }</p>
}

function ReactHooksExplained () {
// Get the context value.
const MoodContextValue = useContext(MoodContext);

return (
// Create context to scope the mood there,
// and not need to use pass props down to the child components.
<MoodContext.Provider value={MoodContextValue}>
<MoodEmoji />
</MoodContext.Provider>
);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const ThemeContext = React.createContext('light');

const Display = () => {
const theme = useContext(ThemeContext);
return <div
style={{
background: theme === 'dark' ? 'black' : 'papayawhip',
color: theme === 'dark' ? 'white' : 'palevioletred',
width: '100%',
minHeight: '200px'
}}
>
{'The theme here is ' + theme}
</div>
}

Performance Hooks

A common way to optimize re-rendering performance is to skip unnecessary work. For example, you can tell React to reuse a cached calculation or to skip a re-render if the data has not changed since the previous render.

To skip calculations and unnecessary re-rendering, use one of these Hooks:

  • useMemo lets you cache the result of an expensive calculation.
  • useCallback lets you cache a function definition before passing it down to an optimized component.

Sometimes, you can’t skip re-rendering because the screen actually needs to update. In that case, you can improve performance by separating blocking updates that must be synchronous (like typing into an input) from non-blocking updates which don’t need to block the user interface (like updating a chart).

To prioritize rendering, use one of these Hooks:

  • useTransition lets you mark a state transition as non-blocking and allow other updates to interrupt it.
  • useDeferredValue lets you defer updating a non-critical part of the UI and let other parts update first.

useMemo

useMemo is a React Hook that lets you cache the result of a calculation between re-renders.

  • MEMOIZATION: cache result of function call, to optimize performance
  • CAUTION: this only used as needed for expensive computations

An example of using useMemo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// When data changes re-render de UI
const [count, setCount] = useState(0)

// MEMOIZATION: cache result of function call, to optimize performance
// CAUTION: this only used as needed for expensive computations
const expensiveCount = useMemo(() => {
return count ** 2
}, [count]) // RECOMPUTE: when count changes

return (
<div className="App">
<div>{count}</div>
</div>
)

useCallback

useCallback is a React Hook that lets you cache a function definition between re-renders.

An example of useCallback

In this example, the ChildComponent receives the onClick prop from the ParentComponent and uses it to handle a click event on a button element. Because the onClick prop is a memoized callback function, the ChildComponent can safely use it without needing to worry about unnecessary re-renders due to changes in the function reference.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// Maybe we want to memoize the function, passing the function to multiple child components,
// especially with big lists, wrapping the function with avoid unnecessary re-rendering in the child components
// because is using always the same function object.

import React, { useState, useCallback } from 'react';
import ChildComponent from './ChildComponent';

function ParentComponent() {
const [count, setCount] = useState(0);

// Define a memoized callback function using the useCallback hook
const handleClick = useCallback(() => {
setCount(prevCount => prevCount + 1);
}, []);

return (
<div>
<p>Count: {count}</p>
<ChildComponent onClick={handleClick} />
</div>
);
}

function ChildComponent({ onClick }) {
return (
<button onClick={onClick}>
Click me!
</button>
);
}

useDeferredValue

The useDeferredValue Hook is a new addition to React 18 and it lets you defer updating a part of the UI.

  const deferredValue = useDeferredValue(value)

useDeferredValue allows you to defer the rendering of a value until a future point in time, which can be incredibly useful in situations where you want to avoid unnecessary rendering.

1
2
3
4
5
6
const [valueToDefer, setValueToDefer] = useState("")
const deferredValue = useDeferredValue(valueToDefer)

return (
<p>{deferredValue}</p>
)

By using the useDeferredValue Hook, you can avoid this problem by deferring the rendering of the search results until the user stops typing. This is similar to how debouncing works; it can dramatically improve performance.

The following example shows how to use the useDeferredValue Hook to simulate a debouncing pattern retrieving Star War’s characters names.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import { useDeferredValue, useEffect, useState } from "react"

function UseDeferredHook() {
const [searchQuery, setSearchQuery] = useState('')
const deferredSearchQuery = useDeferredValue(searchQuery)
const [resultQuery, setResultQuery] = useState([])

useEffect(() => {
async function fetchPeople() {
if (!searchQuery) {
setResultQuery([])
return
}

const response = await fetch(`https://swapi.dev/api/people/?search=${deferredSearchQuery}`)
const { results } = await response.json()
setResultQuery(results)
}

fetchPeople()
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [deferredSearchQuery])

function handleOnChange(event: any) {
setSearchQuery(event.target.value)
}

return (
<div>
<input type="input" placeholder="Type a character" value={searchQuery} onChange={handleOnChange} />
<ul>
{resultQuery && (resultQuery.map((person : any) => (
<li key={person.name}>{person.name}</li>
)))}
</ul>
</div>
)
}

export default UseDeferredHook

In this example, it’s using the useState hook to manage the searchQuery state, which holds the user’s search input. We’re also using the useDeferredValue hook to create a deferredSearchQuery variable, which we pass to the Star Wars API search endpoint after a 1 second delay.


Other Hooks

These Hooks are mostly useful to library authors and aren’t commonly used in the application code.

  • useDebugValue lets you customize the label React DevTools displays for your custom Hook.
  • useId lets a component associate a unique ID with itself. Typically used with accessibility APIs.
  • useSyncExternalStore lets a component subscribe to an external store.

useDebugValue

useDebugValue is a React Hook that lets you add a label to a custom Hook in React DevTools.

useDebugValue(value, format?)

An example of using useDebugValue

1
2
3
4
5
6
7
8
9
10
11
12
13
// Use in multiple components.
function useDisplayName() {
const [displayName, setDisplayName] = useState<string>();

useEffect(() => {
const data = fetchFromDatabase(props.userId);
setDisplayName(data.id);
}, []);

useDebugValue(displayName ?? 'loading...')

return displayName;
}