Life before hooks was messy, confusing at times and full of repetitive code. With the implementation of React Hooks in early 2019, React v16.8.0 made the library simpler and more efficient. React soon became the most popular client-side framework/library for front-end development.
What are hooks and how did they impact React?
React hooks are special functions that let developers "hook into" React state and lifecycle features from functional components. Hooks allow you to reuse stateful logic without changing your component hierarchy. Hooks help to break down components into smaller functions based on their logic and relation. Hooks thus reduce the need for classes while letting you use more of React's features. They don't require you to learn complex functional or relative programming techniques making react a practical library.
Previously React relied on class components to handle state, and without a simpler stateful primitive other than class components, React relied on creating a good amount of boiler plate to define the components. As a result code became cluttered, debugging became harder and logic becoming confusing. When trying to breakdown larger components proved difficult, as component logic became scattered, many felt that React had too much of a learning curve. More issues arose as learning how this
works in JavaScript, having to remember to bind event handlers and struggling when to use classes over functions continued to deter developers from using the library. However hooks changed things for the better.
When should hooks be used?
Hooks cover all existing use cases for classes as they provide a simpler implementation of state and lifecycle uses.
Displaying a stateful variable like a username
, went from a cluttered logical mess, to a more concise component.
With a simple React class component there is a significant amount of boilerplate needed for the code to run:
import React from 'react'
export default class Example extends React.Component{
constructor(props) {
super(props) ;
this.state = {
username: '',
}
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
this.setState({
username: e.target.value
});
}
render(){
return (
<>
<h1>Welcome, {this.state.username}</h1>
<input
value={this.state.username}
onChange={this.handleChange}
placeholder="Enter Username">
</input>
</>
)
}
}
Understanding how this
works is essential, and the logic could quickly become confusing.
Using React hooks however makes the code quick, simple and allows for an easier understanding of how React state works:
import React, {useState} from 'react'
function App() {
const [username, setUsername] = useState("")
function handleChange(e){setUsername(e.target.value)}
return (
<>
<h1>Welcome, {username}</h1>
<input
value={username}
onChange={handleChange}
placeholder="Enter Username"></input>
</>
)
}
export default App
Hook limitations: Classes allow for more customizable components, when compared to components using hooks. However, the React team thought of this and provided us with a method to create custom hooks.
Main Hooks:
1. useState:
Like any other React hook useState
must be imported from React at the top of the file:
import {useState} from 'react';
Then called at the top level of your component declaring the state variable. When declaring state, specific syntax [
and ]
is required to destructure the array as useState
returns two values in an array:
function Component (){
const [] = useState();
}
The first value is a state variable which, during the first render, will match the initial state that has been passed.
The second is the setter function that lets you update the state to a different value and trigger a re-render:
Note: it is common practice to put set
and then the name of the state variable in camelCase when naming variables.
const [age, setAge] = useState()
A value is then needed for the initial state, this value can be any value type with a special case for functions:
const [name, setName] = useState('Henry')
In order to use the setter function and change the current state of the state variable we must call the set function with some next state:
function handleClick(){
setName('George')
}
Note: when calling the set function the current state does not change the already executing code but rather changes what will be returned on the next render.
When everything is all put together it looks something like this:
import {useState} from 'react'
function Component(){
const [age, setAge] = useState(28);
const [name, setName] = useState(Sam);
function handleClick(){
setAge(22);
setName('George');
}
//...
}
2. useEffect:
This React hooks lets you synchronize a component with an external system.
useEffect
must be imported and called at the top level of your component to declare an Effect:
import {useEffect} from 'react';
function Component () {
useEffect()
}
The useEffect
hook takes two parameters, the first being a setup
function that will handle your effects logic. When the component is first added to the DOM, React will run the setup
function and continue running the function with each re-render.
useEffect( ()=>{console.log('hello'},)
The second parameter is the dependency or dependencies put into an array []
that has been declared previously. If no dependency is specified then the effect will continue executing indefinitely. An empty dependency can be use to execute the effect once on the first render:
useEffect( ()=>{console.log('hello')} , [])
Note: Ensure that when thinking of using the useEffect
hook you are trying to connect your component to some external system. In order to limit any unnecessary renders make sure your objects or other dependencies are necessary.
When everything is put together it looks something like this:
import {useEffect, useState} from 'react';
function Component () {
const [data, setData] = useState({});
useEffect(()=>{
fetch('https://localhost:3000')
.then(r => r.json)
.then( (newData) => setData(newData))
},[])
}
3. useContext:
This React hook lets you read and subscribe to context from your component.
It needs to be imported at the top of the file and called at the top level of the component:
import {useContext} from 'react'
function Component (){
useContext();
}
useContext
takes one parameter, the context that has been previously created with createContext at a previous component higher up on the component tree:
const page = useContext(pageContext)
The returned value will be the context value for the calling component, this value is determined as the closest corresponding Context.provider
above in the tree. When everything is put together it looks something like this:
import { createContext, useContext } from 'react';
const ThemeContext = createContext(null);
function Form() {
return (
<Panel title="Welcome">
<Button>Sign up</Button>
<Button>Log in</Button>
</Panel>
);
};
function Panel({ title, children }) {
const theme = useContext(ThemeContext);
return (
<section className='panel'}>
<h1>{title}</h1>
{children}
</section>
)
};
function Button({ children }) {
const theme = useContext(ThemeContext);
return (
<button className='button'>
{children}
</button>
);
};
function App() {
return (
<ThemeContext.Provider value="dark">
<Form />
</ThemeContext.Provider>
)
};
export default App
For a more in-depth breakdown of these and all other hooks visit the React docs reference page for hooks.
Top comments (0)