Introducing React Hooks
Hooks
are a new addition to React 16.8. They let you use state and other React
features without writing a class.
import React, { useState } from 'react';
function Example() {
// Declare a new state variable, which we'll call "count"
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
This
new function useState is the first “Hook” we’ll learn about, but this example
is just
a
teaser. Don’t worry if it doesn’t make sense yet!
const [count, setCount] = useState(0);
You can start learning Hooks on the next page. On this page, we’ll
continue by explaining why we’re adding Hooks to React and how they can
help you write great applications.
React 16.8.0 is the first release to support Hooks. When
upgrading, don’t forget to update all packages, including React DOM. React Native
supported Hooks since the 0.59 release of React Native.
State Hook
This
example renders a counter. When you click the button, it increments the value:
Here,
useState is a Hook (we’ll talk about what this means in a moment). We call it
inside a function component to add some local state to it.
React
will preserve this state between re-renders. useState returns a pair: the
current state value and a function that lets you update it.
You can
call this function from an event handler or somewhere else. It’s similar to
this.setState in a class, except it doesn’t merge the
old and
new state together. (We’ll show an example comparing useState to this.state in
Using the State Hook.)
The only
argument to useState is the initial state. In the example above,
it is 0
because our counter starts from zero. Note that unlike this.state,
the state
here doesn’t have to be an object — although it can be if you want.
The
initial state argument is only used during the first render.
Declaring
multiple state variables
You can use
the State Hook more than once in a single component:
function ExampleWithManyStates()
{
// Declare multiple state variables!
const [age, setAge] = useState(42);
const [fruit, setFruit] = useState('banana');
const [todos, setTodos] = useState([{ text: 'Learn
Hooks' }]);
// ...
}
The array destructuring syntax lets us give different names to
the state variables we declared by calling useState
.
These names aren’t a part of the useState
API. Instead, React assumes that if you call useState
many times, you do it in the same order during every render. We’ll come back to
why this works and when this is useful later.
But
what is a Hook?
Hooks are
functions that let you “hook into” React state and lifecycle features from
function components. Hooks don’t work inside classes — they let you use React
without classes. (We don’t
recommend rewriting your existing components overnight but you can start
using Hooks in the new ones if you’d like.)
React
provides a few built-in Hooks like useState
. You can also create your own Hooks
to reuse stateful behavior between different components. We’ll look at the
built-in Hooks first.
Effect Hook
You’ve
likely performed data fetching, subscriptions, or manually changing the DOM
from React components before. We call these operations “side effects” (or
“effects” for short) because they can affect other components and can’t be done
during rendering.
The Effect
Hook, useEffect
, adds the ability to
perform side effects from a function component. It serves the same purpose as componentDidMount
, componentDidUpdate
, and componentWillUnmount
in React classes,
but unified into a single API. (We’ll show examples comparing useEffect
to these methods in Using the Effect Hook.)
For example,
this component sets the document title after React updates the DOM:
import React, { useState, useEffect } from 'react';
function
Example()
{
const
[count
, setCount
]
=
useState(0);
// Similar to componentDidMount and componentDidUpdate: useEffect(() => { // Update the document title using the browser API document.title = `You clicked ${count} times`; });
return
(
<div>
<p>You clicked {count
} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
When you
call useEffect
, you’re telling
React to run your “effect” function after flushing changes to the DOM. Effects
are declared inside the component so they have access to its props and state.
By default, React runs the effects after every render — including the first
render. (We’ll talk more about how this compares to class lifecycles in Using the Effect Hook.)
Effects may
also optionally specify how to “clean up” after them by returning a function.
For example, this component uses an effect to subscribe to a friend’s online
status, and cleans up by unsubscribing from it:
import React
,
{ useState
, useEffect
}
from
'react';
function
FriendStatus(props)
{
const
[isOnline
, setIsOnline
]
=
useState(null);
function
handleStatusChange(status)
{
setIsOnline(status
.isOnline
);
}
useEffect(() => { ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange); return () => { ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange); }; });
if
(isOnline
===
null)
{
return
'Loading...';
}
return isOnline
?
'Online'
:
'Offline';
}
In this
example, React would unsubscribe from our ChatAPI
when the component unmounts,
as well as before re-running the effect due to a subsequent render. (If you
want, there’s a way to tell
React to skip re-subscribing if the props.friend.id
we passed to ChatAPI
didn’t change.)
Just like
with useState
, you can use more
than a single effect in a component:
function
FriendStatusWithCounter(props)
{
const
[count
, setCount
]
=
useState(0);
useEffect(() => { document
.title
=
`You clicked ${count} times`;
});
const
[isOnline
, setIsOnline
]
=
useState(null);
useEffect(() => { ChatAPI
.subscribeToFriendStatus(props
.friend
.id
, handleStatusChange
);
return
()
=>
{
ChatAPI
.unsubscribeFromFriendStatus(props
.friend
.id
, handleStatusChange
);
};
});
function
handleStatusChange(status)
{
setIsOnline(status
.isOnline
);
}
// ...
Hooks let you organize side effects in a component by
what pieces are related (such as adding and removing a subscription), rather
than forcing a split based on lifecycle methods.
Rules of Hooks
Hooks are
JavaScript functions, but they impose two additional rules:
- 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. (There is just one other valid place to call Hooks — your own
custom Hooks. We’ll learn about them in a moment.)
We provide a
linter plugin to enforce these rules automatically. We
understand these rules might seem limiting or confusing at first, but they are
essential to making Hooks work well.