After this lesson you will be able to:
- Understand what are React Hooks and why are so hot 🔥
- Understand how to use
useState()
- Understand how to use
useEffect()
- Understand how to use
useContext()
- Learn how to create your own custom hook
We've learned how to write React in a 2018 way, so now we'll learn how to write code as a 2019 hipster react developer
do
Hooks are a new addition in React 16.8. They let you use state and other React features without writing a class.
Hooks are the way to access to the features of a class component without writing one. Amazing, right?
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.
Returns a stateful value, and a function to update it.
During the initial render, the returned state (state) is the same as the value passed as the first argument (initialState).
The setState function is used to update the state. It accepts a new state value and enqueues a re-render of the component.
const [state, setState] = useState(initialValue)
import React, { Component } from 'react'
class App extends Component {
state = {
counter: 0
}
increment = () => {
this.setState(prevState => {
return prevState.counter++
})
}
decrement = () => {
this.setState(prevState => {
prevState.counter--
})
}
render() {
const { counter } = this.state
return (
<>
<h1>Counter: {counter}</h1>
<button onClick={this.increment}>+</button>
<button onClick={this.decrement}>-</button>
</>
)
}
}
import React, { useState } from 'react'
function App() {
const [counter, setCount] = useState(0)
const increment = () => {
setCount(prevState => prevState + 1)
}
const decrement = () => {
setCount(prevState => prevState - 1)
}
return (
<>
<h1>Counter: {counter}</h1>
<button onClick={increment}>+</button>
<button onClick={decrement}>-</button>
</>
)
}
Accepts a function that contains imperative, possibly effectful code.
useEffect(didUpdate)
Mutations, subscriptions, timers, logging, and other side effects are not allowed inside the main body of a function component (referred to as React’s render phase). Doing so will lead to confusing bugs and inconsistencies in the UI.
Instead, use useEffect. The function passed to useEffect will run after the render is committed to the screen. Think of effects as an escape hatch from React’s purely functional world into the imperative world.
By default, effects run after every completed render, but you can choose to fire it only when certain values have changed.
import React, { useEffect } from 'react'
function App() {
useEffect(() => {
// This changes the title of the document after the completed render
document.title = "Hello Ironhacker";
}, []);
return (
<>
<h1>Hello Ironhackers</h1>
</>
);
}
Accepts a context object (the value returned from React.createContext
) and returns the current context value for that context. The current context value is determined by the value
prop of the nearest <MyContext.Provider>
above the calling component in the tree.
const value = useContext(MyContext);
When the nearest <MyContext.Provider>
above the component updates, this Hook will trigger a rerender with the latest context value
passed to that MyContext
provider.
Don’t forget that the argument to useContext
must be the context object itself:
- Correct:
useContext(MyContext)
- Incorrect:
useContext(MyContext.Consumer)
- Incorrect:
useContext(MyContext.Provider)
A component calling useContext
will always re-render when the context value changes. If re-rendering the component is expensive, you can optimize it by using memoization.
Building your own Hooks lets you extract component logic into reusable functions.
Traditionally in React, we’ve had two popular ways to share stateful logic between components: render props and higher-order components. We will now look at how Hooks solve many of the same problems without forcing you to add more components to the tree.
When we want to share logic between two JavaScript functions, we extract it to a third function. Both components and Hooks are functions, so this works for them too!
A custom Hook is a JavaScript function whose name starts with ”use” and that may call other Hooks.
Unlike a React component, a custom Hook doesn’t need to have a specific signature. We can decide what it takes as arguments, and what, if anything, it should return. In other words, it’s just like a normal function. Its name should always start with use so that you can tell at a glance that the rules of Hooks apply to it.
function useForm() {
const [form, setForm] = useState({
name: "",
email: "",
password: ""
})
const onChange = e => {
e.persist()
setForm(prevState => ({
...prevState,
[e.target.name]: e.target.value
}))
};
const { name, email, password } = form;
return {
form,
onChange,
name,
email,
password
}
}
function App() {
const {name, email, password, onChange} = useForm()
return (
<>
<input type="text" placeholder="Name" name="name" onChange={onChange}/>
<br />
<input type="email" placeholder="Email" name="email" onChange={onChange}/>
<br />
<input type="password" placeholder="Password" name="password" onChange={onChange} />
<br />
<br />
<p>Name: {name}</p>
<p>Email: {email}</p>
<p>Password: {password}</p>
</>
)
}