Before React 16.8, when hooks in React were not introduced, managing state and using lifecycle methods were only possible by the Class Components that tend to complicate things as we move with our App in React.
But after the introduction of hooks in version 16.8, managing state and using lifecycles methods became the easiest things to do in a React App, and it is only that which keeps our code clean and readable, without that ‘this’ keyword which was there in almost every other line.
In this blog, we will discuss everything related to hooks. Let’s begin
Index
What are hooks?
As already told, hooks are an addition to the Functional Components through which we can work with states and other React features without first converting them into classes as it was the general condition in Class Components.
One point to note is that we don’t have to make any other change in our component except for one thing, we have to write our Apps in functional components as hooks can’t be used in Class Components.
Introduction of Hooks in functional components does not mean the end of Class Components, developers of React gave us an option that we can do everything including managing state and lifecycle methods using both the Components, and it is up to us which one we prefer to use.
Why were hooks introduced?
There were many problems that developers were facing while using the Class Components. They vary depending upon the user and the type of App they are making.
According to the official documentation, “Hooks solve a wide variety of seemingly unconnected problems in React that we’ve encountered over five years of writing and maintaining tens of thousands of components. Whether you’re learning React, use it daily, or even prefer a different library with a similar component model, you might recognize some of these problems.”
Some of the problems that the developers found were –
Reusing Stateful Logic between Components
We all know that the only way to reuse stateful components is by using high-order components and render methods, but this makes our code way more complicated as it requires restructuring our components which can become pretty difficult to follow while debugging.
We can even filter out these components, but a wrapper hell is bound to happen. This problem was solved by hooks, as now we can easily break large components into smaller ones. This way, we can extract stateful logic from components without disturbing the hierarchy of our App.
Dealing with Complex Situations
Passing stateful logic using HOC and render method can sometimes become one big hell that can’t be solved without changing the structure of our App.
These problems can even occur with lifecycles methods like data fetching in ComponentDiMount situations like these are hard to handle as we cannot break a component into smaller ones to make it easy to understand.
Similarly, with the Apps hierarchy – it has to be changed after which it becomes difficult to track the code if we have to debug it.
The solution we developers came up with was using an external library for this, but maintaining it with our Application is not easy as we have to jump between two files over and over to manage them.
But, hooks came with the solution to this problem too, as it lets us break a large Component into smaller ones, and lets us deal with them individually.
Use of ‘this’ keyword in Class Components
‘This’ keyword is one of the most complicated keywords in programming languages as it has different uses depending upon the languages in which it is used.
Not only that, there were many problems with Class Components like flaky reloading. In comparison to that, we found dealing with props, states, and the flow of data much easier than classes.
Hooks can help us with that too, as it helps us deal with states, props, and other features of React without even using classes, and also gave us a way to use many of the React features without even sacrificing our logic.
Types of Hooks
There are many different hooks with different uses, but the most common ones are the useState() hook and useEffect() hook which we will briefly in this blog.
useState() hook
As the name suggests, it is a hook given to us to manage all our state management problems that we were facing with class components.
This is the first step to eliminate the use of this keyword that we used while managing states in Class Components – this.state.name and this.setState.
It will be better if we understand this with the help of an example.
In this example, we are making a simple counter whose initial value is zero that will be increased by one as we click the button.
It is clear from the above comparison that functional components are straightforward in managing states, and we dont have to use the ‘this’ keyword anymore for defining/calling the states.
To understand the useState() hook in detail, click here.
useEffect() hook
This hook allows us to perform side effects like data fetching, changing DOM structure using components, etc, which were only possible in Class Components using lifecycle methods. In other words, this hook serves the same purpose as lifecycle methods in Class Components.
Let’s understand this hook briefly with an example
import React, { useState, useEffect } from 'react';
function CounterExample() {
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>
);
}
export default CounterExample;
In this example, the counter will be updated using the useState hook, but the useEffect() hook will change the title of the app according to the message and the number our counter is showing currently – the updated value.
You can read this blog for a more detailed explanation of the useEffect hook.
Custom Hooks
With the introduction of hooks, we have been given the power by the developers of React to develop our hooks and use it is as we see fit in our app, we just have to follow one extra rule – that the name given to the hook should start from the word use like useState and useEffect, and should follow camel case in their naming.
Click here for a detailed blog on how to make your custom hook with example
Rules for Hooks
There are only two rules which have to be followed for applying hooks in our app –
1. Only call hooks at the top
According to it, hooks should only be called at the top of the function so that they can re-render with the component.
Calling hooks anywhere else except at the top of the function will give us an error. The below image will make this statement clear to you.
According to the error message, hooks can’t be called in a condition statement, loop, and in a nested statement. They are always called at the top of the function.
The second states that hooks must be called in an order, which we have already discussed in our previous blog that you can read here.
That’s what allows React to preserve the state between every re-render.
2. Only call hooks in React Functions
It is clear from the heading itself that we cannot call hooks inside a class component.
Order in which Hooks are rendered
There is always a specific order to call anything and to get the most out of it. The same thing applies to both of our components – Class and Functional.
While creating the class components, there is a certain ordering that optimizes the React application code.
First, we call the constructor for initialization, then the lifecycle functions, followed by any functions relevant to the component’s job. Finally, you write the render
method:
const propTypes = {
id: PropTypes.number.isRequired,
url: PropTypes.string.isRequired,
text: PropTypes.string,
};
const defaultProps = {
text: 'Hello World',
};
class Link extends React.Component {
static methodsAreOk() {
return true;
}
constructor(props) {
super(props)
this.state = {
user = null
}
}
componentDidMount() {
console.log('component did mount')
}
componentDidUpdate() {
console.log('component did update')
}
componentWillUnmount() {
console.log('component will unmount')
}
render() {
return <a href={this.props.url}>{this.props.text}</a>
}
}
Link.propTypes = propTypes
Link.defaultProps = defaultProps
export default Link
When writing function components, there is no constructor and lifecycle method, so you might be confused because the structure isn’t as enforced as in a class component:
function App() {
const [user, setUser] = useState(null);
useEffect(() => {
console.log("component is mounted");
}, []);
const [name, setName] = useState('');
return <h1>React component order</h1>;
}
But just like with class components, creating a defined structure for your function components will help your project’s readability.
It’s recommended to first declare state variables with useState
hook, then write the subscriptions with useEffect
hook followed by any function relevant to the component’s job.
Then finally, you return the elements to be rendered by the browser:
function App() {
const [user, setUser] = useState(null);
const [name, setName] = useState('');
useEffect(() => {
console.log("component is mounted");
}, []);
return <h1>React component order</h1>;
}
By enforcing a structure, you will keep the flow of your code consistent and familiar across many components to learn more about the order of calling hooks, read here.
Conclusion
- Hooks are only available for Functional Components and versions higher than 16.8 or higher
- We don’t have to re-write our whole components, we can easily add them anywhere without harming or changing our entire structure.
- With hooks, we can break components into smaller ones to make it easier to understand the App.
- There are no plans for removing Class Components after the introduction of Hooks
- Hooks gives us a direct way to deal with APIs, states, props, and many other things without first converting them into classes.
Hi, There’s no doubt that your blog could be having browser compatibility issues. Whenever I look at your blog in Safari, it looks fine however when opening in Internet Explorer, it has some overlapping issues. I just wanted to provide you with a quick heads up! Other than that, fantastic website!
Thank You for pointing that out. I will work on that.