Hooks are a new feature introduced in the React 16.8 version in 2019. They allow us to use state and other features such as lifecycle without writing a class. Before Hooks were introduced, you had to write a long code, like so:
class Example extends React.Component {
constructor(props) {
super(props);
this.state = { animal: “dog” };
}
or
componentDidMount(),
shouldComponentUpdate(),
componentDidUpdate() or
componentWillUnmount()
…
These are overwhelming to a newbie like me. Now I understand the structure (not fully) and the importance of having that knowledge, but I got the idea after learning and coding with the use of React Hooks.
There are some rules and steps to use Hooks, but there are only a few. Here is an excerpt from React Documentation:
“Only call Hooks at the top level. Don’t call Hooks inside loops, conditions, or nested functions.”
“Only call Hooks from React function components. Don’t call Hooks from regular JavaScript functions.”
When you use a certain Hook, import it from ‘react’ first and call it inside a function component, like so:
import React, { useState } from ‘react’;
function Example () {
const [ name, setName ] = useState(“ ”);
return ( ) //
In some Hooks, we declare the initial state or value in the parentheses right after the Hook name. If it’s a string, we need a quotation mark; if it’s an object, we need curly brackets; if it’s a number, boolean, or null, we write it as it is, and it is used during the first render.
Here are seven built-in Hooks that I learned.
useState
const [ number, setNumber ] = useState(0)
By learning useState I was able to understand what a hook is like. We declare the initial value in the parentheses as I mentioned above, and it is set to the value on the left (number in this case). When an event happens, such as clicking a button, we can update the value by calling setNumber and the new value is set to number.
useEffect
useEffect(( ) => { function }, [ ]) **[ ] is the array of dependencies
The useEffect Hook is used when there are side-effects. A side-effect or simply effect is when an operation has an effect on an output that is outside the intended usage, such as fetching data via API, updating a DOM, or using timers. When and every time there is a change to the component, the component/page renders, so does a side-effect. In order to control this, there are three ways:
No dependencies: useEffect(( ) => { })
The side-effect runs every time the page is updated
An empty dependency array: useEffect(( ) => { }, [ ])
The side-effect runs once
Passing props or states: useEffect(( ) => { }, [ props, state ])
The side-effect runs when props/state updates
Some side-effects need to be cleaned up before the component leaves the screen. This prevents us from memory leaks. In order to do this, we add a return function in the useEffect Hook, like so:
useEffect(( ) => {
// function
return ( ) => cleanup(props) {
// function
}
}, [ ]}
useContext
When we pass data between components, we can do so only from the parent component to the child component. But what if there are more nesting components or levels, like from a parent to its grandchild or great-grandchild? Without using useContext, we declare a state in a parent component (Let’s say ‘App.js’), and pass it to component B, from B to C, from C to D, and finally from D to E, where that state is actually used in the function. Here useContext comes in handy.
(In this example, a value 100 is passed)
<<App.js (parent component)>>
import React, { createContext } from 'react'
import { ComponentB } from './components/ComponentB';
export const ExampleContext = createContext();
function App( ) {
return (
);
};
export default App;
<<Component B (C and D)>>
import React from 'react'
import { ComponentC } from './ComponentC';
export function ComponentB( ) {
return (
<>
</>
);
};
<<Component E>>
import { useContext } from 'react'
import { ExampleContext } from '../App'
export const ComponentE = ( ) => {
const example = useContext(ExampleContext)
return (
{example}
);
};
useReducer
const [state, dispatch] = useReducer(reducer, initialState);
The useReducer Hook manages the state just like useState, but useReducer makes more complex state management possible.
We declare the initialState outside of the ‘main’ function. Then we create a reducer function which takes two arguments, (state, action). We can create several types of actions with the use of a switch statement, and depending on that action type we can set a new state.
For example, in a counter function where we can increase or decrease a number by 1 by clicking a button, and if we want to increase a number, we call dispatch with an action type in its parentheses, just like
dispatch({ type: ‘increment’ })} increment
and the reducer function returns our desired output.
useCallback
const exampleCallback = useCallback(( ) => { //function }, [ ]};
** [ ] is an array of dependencies
The useCallback Hook optimizes the performance by avoiding unnecessary rendering.
It, instead, uses a memorized/cached function unless a value in a dependency array is updated.
useMemo
const exampleValue = useMemo(( ) => function(props), [(props)]}
The useMemo Hook is similar to useCallback. It optimizes the performance by using a memorized/cached value. It renders only when a value in a dependency array is updated.
The difference between useMemo and useCallback:
useMemo: memorize the value/result of a function
useCallback: memorize a function
useRef
const example = useRef( initialValue )
The useRef Hook stores an updated value without re-rendering. It’s similar to useState, but with useState Hook when there is an update in a state, the page is re-rendered even though, in the worst case, the state is the same value. On the other hand, useRef creates an object, { current: …}, and can hold the mutable value. Hence, we can avoid unnecessary rendering.
There is another useful feature. The useRef Hook can access a DOM element, therefore it auto-focuses the input element in the form.
It took time to understand these hooks, but the more I used in my code (with a lot of failures though) the more comfortable and clear I got understanding and making use of them. To me, practice won’t make ‘perfect’, but practice makes me better at coding.
Top comments (0)