React is the most popular front-end framework in the JavaScript ecosystem. It is famous for its ease of use and its readability, allowing companies and startups to adopt it. But classes can be unwieldy and hard to understand. Hooks allow you to use state, lifecycle methods, and other functionalities of React without using classes.
This article will explain what hooks are, what makes them unique, and why they are the best thing to happen to React.
The origin of React hooks
Originally, React mainly used class components, which can be strenuous at times as you always had to switch between classes, higher-order components, and render props. With React hooks, you can now do all these without switching, using functional components. Hooks make React so much better because you have simpler code that implements similar functionalities faster and more effectively. You can also implement React state and lifecycle methods without writing classes.
Below are code examples to illustrate React class and functional components.
import React, { Component } from 'react'
export default class Hello extends Component {
render() {
return(
<div>
Hello World!
</div>
)
}
}
The code above is a class component that prints “Hello World” in the DOM.
import React from 'react'
export default function Hello() {
return (
<div>
Hello World!
</div>
)
}
The code above is a functional component that prints “Hello World” on the DOM.
Comparing both sets of code above, the functional component has significantly simpler code that performs the same function; there’s no need to allocate space to a class instance, then call a render() function, you just call the function. React hooks have so many benefits and functions they perform, but one of the big ones is to make the React lifecycle methods easier.
NOTE: You cannot use React hooks on class components.
How have hooks made the React lifecycle easier?
The various lifecycle methods in React include mounting, updating, and unmounting.
- Mounting inserts elements into the DOM.
- Updating as the name implies, updates elements in the DOM.
- Unmounting removes elements from the DOM.
Below is an illustration of the various React lifecycle methods:
Initially, you could only use these lifecycle methods with class components, which usually comprise a lot of carefully engineered code that is more difficult to write or understand than when you use hooks to implement them as functional components.
Take, for instance, if you try to fetch user data using a componentDidMount() in a class component like in the code below:
import React, { Component } from 'react'
import Axios from 'axios'
export default class Hello extends Component {
constructor(props) {
super(props);
this.state = { name: ""};
}
componentDidMount() {
Axios.get('/api/user/name')
.then(response => {
this.setState({ name: response.data.name })
})
}
render() {
return (
<div>
My name is {this.state.name}
</div>
)
}
}
Now let’s compare it to doing the same thing with a functional component by using the useState and useEffect hooks in the code below:
import React, { useEffect, useState } from 'react'
import Axios from 'axios'
export default function Hello() {
const [Name, setName] = useState("")
useEffect(() => {
Axios.get('/api/user/name')
.then(response => {
setName(response.data.name)
})
}, [])
return (
<div>
My name is {Name}
</div>
)
}
The code above collects user data by using the Axios API and prints it on the DOM. The useEffect and useState hooks make for more straightforward and concise code that is easy to understand and work on than the class components. When using lifecycle in class components, the componentDidMount(), componentDidUpdate(), componentWillUnmount() methods are handled individually, but when using React hooks, you can just do everything through the useEffect hook.
Hooks have made React easier to learn for beginners
Class components have always been a little cumbersome and confusing, especially as it makes state management and code reuse look so much more complicated than it actually is. That made many beginner developers shy away from React and opt for an “easier” framework. With hooks, it’s now simpler to learn React; because of this, its use in the tech world today has grown:
The graph above shows the increase in the percentage of Stack Overflow questions about React over the years vs. other popular JavaScript frameworks, proving that its general usage has increased since the introduction of hooks.
Some hooks and their functions
Before hooks were introduced, organizing components by lifecycle methods forced us to sprinkle similar logic in several components i.e. writing the same code in several places. To solve this and other superficial problems, React embraced functions for more straightforward and more flexible code. The next issue they had to solve was how to change the state of our components. This now brings us to our first hook: useState.
The useState Hook
Arguably the most common React hook, useState helps you pass in state variables in a functional component. Take a look at the code below:
const loadingTuple = React.useState(true)
const loading = loadingTuple[0]
const setLoading = loadingTuple[1]
loading // true
setLoading(false)
loading // false
In the code above, useState takes a single argument: the state’s initial value. It returns an array with a state variable and a function to update that state. You now have everything you need to update the state of your functional component.
The next hook we will look into solves the problem of implementing lifecycles in a functional component. It’s called useEffect.
The useEffect Hook
The useEffect helps to perform side effects in functional components; that is, any function that you need to run after updating the DOM. It replaces some events by running a function whenever one or more variables change. It takes two arguments: a function and an optional array. The function defines which “side effect” to run, and the optional array indicates variables, objects, etc., to watch for changes.
Other React hooks include:
- useContext(): This hook helps to build a context API, which itself is a mechanism used to share data without passing props.
- useRef(): This hook allows you to reference the DOM in the functional component directly.
Note: useRef() doesn’t trigger a re-render like setState() does.
- useReducer(): This stores the current state value. You can liken it to Redux.
- useMemo(): This is a hook used to return a memoized value, i.e. when you need your function to return a cached value.
- useCallback: This hook is used when you have a component’s child continuously re-rendering. It will then return a memoized version of the callback that only changes when one of the dependencies changes.
These are just some of the most commonly used React hooks. If you want to learn more about React hooks, you can check it out here.
Conclusion
We used classes for React components because it was the best way at the time as we couldn’t create a state or implement the lifecycle methods in functional components. React hooks have made performing these functionalities much easier by providing an avenue for simpler, more composable, flexible, and extendable code than using class components without hooks. Many companies have adopted React as their primary front-end framework, which makes more developers add it to their skill-set. If you have any questions, leave a comment below!