React Hooks
Hooks are a new addition in React 16.8. They allow you use state, life cycle methods and other React features without writing a class component. If we are using hooks we can have only a functional component in the entire application. For more detail explanation you check React documentation.
Different hooks have been introduced to React: Basic hooks and additional hooks
Basic Hooks
The basic hooks are:
- useState
- useEffect
- useContext
State Hook
Using hooks we can access state.
To use hooks, first we should import the useState
hooks from react. The useState is a function which takes one argument (the initial value) and returns an array of the current state and a function that lets you update it.
State with Data Types
If you use useState
with primitive data types, there is no problem by using operators to set the state with the current value, like in our example above.
But if you use non-primitive data types you can't just change the value and set it.
Note
The reason is that React compares object by strict equality ===
.
Strict equality works for strings, numbers and booleans.
For example for strings:
For example for numbers:
For example for booleans:
But it doesn't work for arrays, objects and functions (functions and arrays are objects under the hood), because JavaScript compares the memory address of the variable containing arrays, objects and functions.
For example for arrays:
For example for objects:
const one = { one: 'value' }
const anotherOne = { one: 'value' }
const two = { two: 'value' }
one !== anotherOne
one !== two
For example for functions:
You have to create a "new" object or copy the old one and set it.
Here is a bad example, which won't work:
Here is the fixed example:
The same happens to arrays:
Here is the fixed examle:
When a state changes, React will check if the state is used somewhere and update the element.
Effect Hook
Effects happen, when a state or a prop changes.
To watch for changes and do a sideeffect (not computing a value or not preparing a callback) you can use useEffect
.
Context
useContext
will be discussed later in the Context chapter.
Additional Hooks
Additional Hooks can be used to express specific statements or to speed up your code.
- useReducer
- useCallback
- useMemo
- useRef
- useImperativeHandle
- useLayoutEffect
- useDebugValue
- useDeferredValue
- useTransition
- useId
Reducer
Reducer are handy if you have multiple actions for the same state. For example, if you work on the same state with different functions, then a reducer can be used to define the actions on a state in one place:
Callbacks
Callbacks are important to pass a behaviour into a component from an outer scope. Let's check this example first:
You see that an update of our states results in an update for our buttons.
Let's improve the code by using useCallback
to listen for specific changes:
Now the buttons does not update if the other button gets clicked. This can lead to massive performance improvements.
Memo
If you have some operations, which take a lot of computing time, useMemo
.
Actually I would say, use always useMemo
if you calculate something depending on a state or prop.
Here is a bad example:
Here we use useMemo
, additionally we define the dependency:
Ref
What if you need to access to the actual html element in the dom, to call a function on the element?
You can useRef
for that:
Imperative Handle
Layout Effect
useLayoutEffect
works the same way useEffect
works.
The signature is identical to useEffect, but it fires synchronously after all DOM mutations.
Use this to read layout from the DOM and synchronously re-render.
Updates scheduled inside useLayoutEffect will be flushed synchronously, before the browser has a chance to paint.
Debug Value
useDebugValue
shows a value in React DevTools.
function useFriendStatus(friendID) {
const [isOnline, setIsOnline] = useState(null)
// Show a label in DevTools next to this Hook // e.g. "FriendStatus: Online"
useDebugValue(isOnline ? 'Online' : 'Offline')
return isOnline
}
Deferred Value
useDeferredValue
receives a state variable and returns a new state variable, which will wait until all rendering finishes for the given state variable and then rerenders the deferred value.
function Typeahead() {
const query = useSearchQuery('')
const deferredQuery = useDeferredValue(query)
// Memoizing tells React to only re-render when deferredQuery changes,
// not when query changes.
const suggestions = useMemo(
() => <SearchSuggestions query={deferredQuery} />,
[deferredQuery],
)
return (
<>
<SearchInput query={query} />
<Suspense fallback="Loading results...">{suggestions}</Suspense>
</>
)
}
Transition
useTransition
can handle loading states.
ID
useId
is a hook for generating unique IDs that are stable across the server and client, while avoiding hydration mismatches.
Warning
useId
is not for generating keys in a list. Keys should be generated from your data.