Just a few weeks until the 2021 JavaScript Full-Stack Bootcamp opens.
Signup to the waiting list!
Hooks is a feature that will be introduced in React 16.7, and is going to change how we write React apps in the future.
Before Hooks appeared, some key things in components were only possible using class components: having their own state, and using lifecycle events. Function components, lighter and more flexible, were limited in functionality.
Hooks allow function components to have state and to respond to lifecycle events too, and kind of make class components obsolete. They also allow function components to have a good way to handle events.
Access state
Using the useState()
API, you can create a new state variable, and have a way to alter it. useState()
accepts the initial value of the state item and returns an array containing the state variable, and the function you call to alter the state. Since it returns an array we use array destructuring to access each individual item, like this: const [count, setCount] = useState(0)
Here’s a practical example:
import { useState } from 'react'
const Counter = () => {
const [count, setCount] = useState(0)
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>Click me</button>
</div>
)
}
ReactDOM.render(<Counter />, document.getElementById('app'))
You can add as many useState()
calls you want, to create as many state variables as you want. Just make sure you call it in the top level of a component (not in an if
or in any other block).
Example on Codepen:
See the Pen React Hooks example #1 counter by Flavio Copes (@flaviocopes) on CodePen.
Access lifecycle hooks
Another very important feature of Hooks is allowing function components to have access to the lifecycle hooks.
Using class components you can register a function on the componentDidMount
, componentWillUnmount
and componentDidUpdate
events, and those will serve many use cases, from variables initialization to API calls to cleanup.
Hooks provide the useEffect()
API. The call accepts a function as an argument.
The function runs when the component is first rendered, and on every subsequent re-render/update. React first updates the DOM, then calls any function passed to useEffect()
. All without blocking the UI rendering even on blocking code, unlike the old componentDidMount
and componentDidUpdate
, which makes our apps feel faster.
Example:
const { useEffect, useState } = React
const CounterWithNameAndSideEffect = () => {
const [count, setCount] = useState(0)
const [name, setName] = useState('Flavio')
useEffect(() => {
console.log(`Hi ${name} you clicked ${count} times`)
})
return (
<div>
<p>
Hi {name} you clicked {count} times
</p>
<button onClick={() => setCount(count + 1)}>Click me</button>
<button onClick={() => setName(name === 'Flavio' ? 'Roger' : 'Flavio')}>
Change name
</button>
</div>
)
}
ReactDOM.render(
<CounterWithNameAndSideEffect />,
document.getElementById('app')
)
The same componentWillUnmount
job can be achieved by optionally returning a function from our useEffect()
parameter:
useEffect(() => {
console.log(`Hi ${name} you clicked ${count} times`)
return () => {
console.log(`Unmounted`)
}
})
useEffect()
can be called multiple times, which is nice to separate unrelated logic (something that plagues the class component lifecycle events).
Since the useEffect()
functions are run on every subsequent re-render/update, we can tell React to skip a run, for performance purposes, by adding a second parameter which is an array that contains a list of state variables to watch for.
React will only re-run the side effect if one of the items in this array changes.
useEffect(
() => {
console.log(`Hi ${name} you clicked ${count} times`)
},
[name, count]
)
Similarly, you can tell React to only execute the side effect once (at mount time), by passing an empty array:
useEffect(() => {
console.log(`Component mounted`)
}, [])
useEffect()
is great for adding logs, accessing 3rd party APIs and much more.
Example on Codepen:
See the Pen React Hooks example #3 side effects by Flavio Copes (@flaviocopes) on CodePen.
Enable cross-component communication using custom hooks
The ability to write your own hooks is the feature that is going to significantly alter how you write React apps in the future.
Using custom hooks you have one more way to share state and logic between components, adding a significant improvement to the patterns of render props and higher-order components. Which are still great, but now with custom hooks have less relevance in many use cases.
How do you create a custom hook?
A hook is a function that conventionally starts with use
. It can accept an arbitrary number of arguments, and return anything it wants.
Examples:
const useGetData() {
//...
return data
}
or
const useGetUser(username) {
//...const user = fetch(...)
//...const userData = ...
return [user, userData]
}
In your own components, you can use the hook like this:
const MyComponent = () => {
const data = useGetData()
const [user, userData] = useGetUser('flavio')
//...
}
When exactly to add hooks instead of regular functions should be determined on a use case basis, and only experience will tell.
Download my free React Handbook
The 2021 JavaScript Full-Stack Bootcamp will start at the end of March 2021. Don't miss this opportunity, signup to the waiting list!
More react tutorials:
- A React simple app example: fetch GitHub users information via API
- Build a simple counter with React
- VS Code setup for React development
- How to pass props to a child component via React Router
- Create an app with Electron and React
- Tutorial: create a Spreadsheet using React
- The roadmap to learn React
- Learn how to use Redux
- Getting started with JSX
- Styled Components
- Introduction to Redux Saga
- Introduction to React Router
- Introduction to React
- React Components
- The Virtual DOM
- React Events
- The React State
- React Props
- The React Fragment
- The React Context API
- React PropTypes
- React concepts: declarative
- React: How to show a different component on click
- How to loop inside React JSX
- Props vs State in React
- Should you use jQuery or React?
- How much JavaScript you need to know to use React?
- Introduction to Gatsby
- How to reference a DOM element in React
- Unidirectional Data Flow in React
- React Higher Order Components
- React Lifecycle Events
- React Concept: Immutability
- React Concept: Purity
- Introduction to React Hooks
- Introduction to create-react-app
- React Concept: Composition
- React: Presentational vs Container Components
- Code Splitting in React
- Server Side Rendering with React
- How to install React
- CSS in React
- Using SASS in React
- Handling Forms in React
- React StrictMode
- React Portals
- React Render Props
- Testing React components
- How to pass a parameter to event handlers in React
- How to handle errors in React
- How to return multiple elements in JSX
- Conditional rendering in React
- React, how to transfer props to child components
- How to get the value of an input element in React
- How to use the useState React hook
- How to use the useCallback React hook
- How to use the useEffect React hook
- How to use the useMemo React hook
- How to use the useRef React hook
- How to use the useContext React hook
- How to use the useReducer React hook
- How to connect your React app to a backend on the same origin
- The Reach Router Tutorial
- How to use the React Developer Tools
- How to learn React
- How to debug a React application
- How to render HTML in React
- How to fix the `dangerouslySetInnerHTML` did not match error in React
- How I fixed an issue with a React login form state and Browser autofill
- How to configure HTTPS in a React app on localhost
- How to fix the "cannot update a component while rendering a different component" error in React
- Can I use React hooks inside a conditional?
- Using useState with an object: how to update
- How to move around blocks of code with React and Tailwind
- React, focus an item in React when added to the DOM
- React, edit text on doubleclick
- React Router, how to get data from a dynamic route
- React Router, why useLocation and useHistory might return undefined