How to Convert React Components from Class to Functional with Hooks

AlishaS
Bits and Pieces
Published in
11 min readMar 25, 2023

--

In React 16.8, hooks are a brand-new feature. They provide state and other React capabilities without the need for class creation.

With React 16.7, we can now convert class-based components to functional components using the new React Hooks. This enables us to use the benefits of both types of components in one project, which is great! We’ll no longer need to create separate files for each type of component and make sure we import them in the correct places — it’s all in one place now. The only issue is that for some developers, this might feel like a backward step. Particularly if you have gotten comfortable with writing your own custom hooks (e.g., with Recompose).

Why You’d Convert Class Components to Hooked Functional Components

If you have already started practising React Hooks in your project, then you’ll be familiar with the benefits that come with using Hooks. Hooks let you export and import only the components you need from a file, as opposed to importing everything like you would with class-based components. This is beneficial for two reasons. Firstly, it means that your components are reusable. You can import a component from one file and use it in another file if the component doesn’t contain information that is specific to the file like class-based components do. Secondly, it means that your file sizes will be smaller. Hooked components only import what they need for a certain use case, which keeps the file size smaller. Hooks are also easier to test due to the isolation of each component, whereas with class-based components, testing every component in one file can be difficult.

Converting class-based components to functional components gives some benefits -

  • Easier to organize your code — You don’t need to create a separate file for every component type in your project — everything is in one file, which makes it easier to navigate your code base.
  • Code is easier to read — You don’t have to scroll through hundreds of lines of code to see what each component is doing, as all of your components will be in one place.
  • Code is easier to maintain — If you decide to remove a component from your project, then you only have to delete it from one place. With class-based components, you may have to go through and delete the component from each file where it is being used, which can be time-consuming.
  • Consistent naming — All of your components will be named the same, which is easier when it comes to reading other people’s code.
  • Easier to refactor — If you decide to change how a component works, then you only need to make the change in one place. With class-based components, you need to make the change in every file that the component is used.

Converting class-based components to functional components also has some disadvantages-

  • You have to remember to add the export keyword in front of each component that you want to convert to a functional component, or it will still be class-based.
  • You lose the ability to add state to your components that are scoped to the component, which you may have been utilizing before.
  • You have to remember to use unbound event handlers, e.g., event handlers without an “e” suffix, which is something that you don’t have to do when using class components.
  • You have to remember to export your React components if you want to use them with other React libraries, such as with React Native.

The necessary steps that must be considered before altering the class-based components to functional components -

  • Use a function rather than a class.
  • Eliminate the constructor.
  • Preserve the return; delete the render() method.
  • Before all methods, add const.
  • State every time the component.
  • Delete all occurrences of “this” in the component.
  • Use useState to set the starting state.
  • alter this.
  • setState() To update the state, call the function you named in the previous step.
  • useEffect() have to be used instead of componentDidMount and also with componentDidUpdate.

The detailed procedures are -

  • Hooked Functionality with React Hooks

Hooks takes the best parts of both functional and class-based components and compile them into one type of component. The hooks for functional components are as follows:

  • Use state: With functional components, we can create a state inside the component. However, it isn’t scoped to the component — it’s scoped to the entire file. With hooks, we can create a state that is scoped to the file. The state is accessible to all of the components in the file.
  • Use React lifecycle methods: Hooked functional components also have access to lifecycle methods, such as componentDidMount and componentDidUnmount. The only difference with these hooks is that they have no “e” suffix. So you would write componentDidMount and not componentDidMount().
  • Confirming Which Hooks You Need and Wrapping Class Components Together with useState, useEffect, and useContext

You may be wondering which hooks you need to use when converting components from class-based to hooked functional components. You need to import useState for every functional component that you want to convert. You need to import useEffect for every functional component that you want to convert that has side effects, and you need to import useContext for every functional component that has side effects and accesses data that is scoped outside the file.

You can wrap these components in another component, like a parent component, to keep the file clean and organized.

  • Converting a Stateful Component to a Function Using useState

Let’s say we have a stateful component that has a specific value for a specific use case. With class-based components, we would create a function that is scoped to that use case, and we would add that function to the file as a class-based component.

With hooked functional components, we can do that but with a function that is scoped to the file. We would add the function to the file as a hooked functional component. This function would then be called when the hooked functional component is used, and the function would return the state that we want to be used when the hooked functional component is used.

In the hooked functional component, we would import the function, and it would appear in our file as a function that has “state” in the name, e.g., getState. The “state” at the end of the function name is important, as it tells React that the function returns the state.

This means that we can replace the function with a variable or a constant in our file and use that instead. The function can be used anywhere in the file, although it may make more sense to place it in another function in the file, depending on the use case.

  • Converting a Render-Only Component to a Function Using useRender

Let’s say we have a component that doesn’t have any state and that only needs to render a React element. With class-based components, we would create a function that is scoped to that use case, and we would add that function to the file as a class-based component.

With hooked functional components, we can do that but with a function that is scoped to the file. This function would then be called when the hooked functional component is used, and the function would return a React element for the hooked functional component to render.

In the hooked functional component, we would import the function, and it would appear in our file as a function that has “render” in the name, e.g., renderElement. The “render” at the end of the function name is important, as it tells React that the function returns a React element.

This means that we can replace the function with an element, a constant, or a variable in our file and use that instead. The function can be used anywhere in the file, although it may make more sense to place it in another function in the file, depending on the use case.

Converting class-based components to functional components -

  1. When no state or life cycle method exists. — Consider the below code of the class-based component.
import React, { Component } from ‘react’;
class App extends Component {
showMessage = () => {
alert(‘You clicked a button.’);
};
render() {
return (
<div>
<h1>Class Component without state or life cycle</h1>
<button onClick={this.showMessage}>
Click me
</button>
</div>
);
}
};
export default App;

When a button is clicked, this code only notifies the message that it was clicked. This must then be transformed into a working component. The necessary stages, which we have already seen above, must be followed. Thus, following the completion of the required processes, the functional components should be as follows:

import React from ‘react’;
function App() {
const showMessage= () => {
alert(‘You clicked a button.’);
};
return (
<div>
<h1>Functional Component without state or life cycle.</h1>
<button onClick={showMessage}>
Click me.
</button>
</div>
);
};
export default App;

2. When there is a state that exists in the class component. — Consider the below code for the class-based component that renders the state.

import React, { Component } from ‘react’;
class App extends Component {
state = {
message: ‘’
}
showMessage = () => {
console.log(this.state.message);
};
handleInput = e => {
this.setState({ message: e.target.value });
};
render() {
return (
<div>
<h1>Class Component with state</h3>
<input
type=”text”
onChange={this.handleInput}
value={this.state.message}
placeholder=”Message”
/>
<button onClick={this.showMessage}>
Click to log message
</button>
</div>
);
}
}
export default App;

This class component logs the input message to the console whenever a button is clicked. The above-mentioned requirements must be followed in order to convert this as well. And once all necessary procedures have been taken, the functional component will be -

import React, { useState } from ‘react’;
function App() {
const [message, setMessage] = useState(‘hello’);
const showMessage= () => {
console.log(name);
};
const handleInput = e => {
setMessage(e.target.value);
};
return (
<div>
<h1>Functional Component with state</h3>
<input
type=”text”
onChange={handleInput}
value={message}
placeholder=”Enter Message”
/>
<button onClick={showMessage}>
Click to log message
</button>
</div>
);
};
export default App;

3. When there exist multiple states in the class components. — The class component has multiple state components. Consider the below code with this.

import React, { Component } from ‘react’;
class App extends Component {
state = {
name: ‘’,
subject: ‘’,
message: ‘’
};
showMessage = () => {
console.log(this.state.name);
console.log(this.state.subject);
console.log(this.state.message);
};
handleUserInput = e => {
this.setState({ e.target.name: e.target.value });
};
render() {
return (
<div>
<h1>Class Component with multiple states</h3>
<input
type=”text”
onChange={this.handleUserInput}
name=’name’
value={this.state.name}
placeholder=”Name”
/>
<input
type=”text”
name=’subject’
onChange={this.handleUserInput}
value={this.state.subject}
placeholder=”Subject”
/>
<input
type=”text”
name=’message’
onChange={this.handleUserInput}
value={this.state.message}
placeholder=”Enter Message”
/>
<button
className=”btn btn-large right”
onClick={this.showMessage}
>
Print messages on log
</button>
</div>
);
}
}
export default App;

The message is entered by the user and recorded in the console by the code in the class mentioned above. Therefore, we must do the same necessary procedures outlined before in order to transform this kind of class-based component. Therefore, after taking the required actions, the functional element for this will be -

import React, { useState } from ‘react’;
function App() {
const [name, setName] = useState(‘’);
const [subject, setSubject] = useState(‘’);
const [message, setMessage] = useState(‘’);
const showMessage= () => {
console.log(name);
console.log(subject);
console.log(message);
};
const handleUserInput = e => {
if(e.target.name === ‘name’)
setName(e.target.value);
else if(e.target.name === ‘subject’)
setSubject(e.target.value);
else if(e.target.name === ‘message’)
setMessage(e.target.name);
};

return (
<div>
<h1>Functional Component with multiple states</h3>
<input
type=”text”
onChange={handleUserInput}
name=’name’
value={name}
placeholder=”Name”
/>
<input
type=”text”
name=’subject’
onChange={handleUserInput}
value={subject}
placeholder=”Subject”
/>
<input
type=”text”
name=’message’
onChange={handleUserInput}
value={message}
placeholder=”Enter Message”
/>
<button
className=”btn btn-large right”
onClick={showMessage}
>
Print messages on log
</button>
</div>
);
};
export default App;

2. When we have the class-based component have componentDidMount() and componentDidUpdate() — Consider the below code for the class-based component.

import React, { Component } from ‘react’;
class App extends Component {
state = {
headElement: ‘InterviewBit React Hooks Interview Questions’
}
componentDidMount() {
const header = document.querySelectorAll(‘#headElement’)[0];
setTimeout(() => {
header.innerHTML = this.state.header;
}, 3000);
}
componentDidUpdate() {
const node = document.querySelectorAll(‘#headElement’)[0];
node.innerHTML = this.state.header;
}
handleUserInput = e => {
this.setState({ headElement: e.target.value });
};
render() {
return (
<div>
<h1 id=”headElement”>Class Component with mount and update</h3>
<input
type=”text”
onChange={this.handleUserInput}
value={this.state.header}
/>
</div>
);
}
}
export default App;

The code of the heading 1 is updated with the new user-inputted text via the aforementioned class-based component. ComponentDidMount() and ComponentDidUpdate are used to do this (). Using the user interface’s current state, aids in updating the user interface’s state.

Therefore, the same procedures must be used to transform this class-based component into a functional component. Only the useEffect() hooks for componentDidMount() and componentDidUpdate() need to be modified. Therefore, the final functional element will be -

import React, { useState, useEffect } from ‘react’;
function App() {
const [head, setHead] = useState(‘InterviewBit React Hooks Interview Questions’);
useEffect(() => {
const newhead = document.querySelectorAll(‘#headElement’)[0];
setTimeout(() => {
newheader.innerHTML = head;
}, 2000);
});
const handleUserInput = e => {
setHead(e.target.value);
};
return (
<div>
<h1 id=”headElement”>Functional Component with useEffect</h1>
<input
type=”text”
onChange={handleUserInput}
value={head}
/>
</div>
);
};
export default App;

💡 And when you’ve converted your class components to functional components or custom hooks, you can isolate and extract them into packages, so you can use an open-source toolchain like Bit to publish, version, and reuse it across all of your projects with a simple npm i @bit/your-username/YourComponent. Find out more here, and here.

Conclusion

The majority of the React community is moving away from class-based components and toward functional-based components. Compared to class-based components, which we have already examined in this article, functional-based components offer a number of benefits.

Following several procedures that we have already covered in this article, the process of changing class-based components to functional-based components begins. If you were asked these questions in the initial interview, the interviewer may have a wonderful opinion of you because of it. When preparing for the React hooks interview, there are plenty of other questions you need to address. Learn more.

Build Apps with reusable components, just like Lego

Bit’s open-source tool help 250,000+ devs to build apps with components.

Turn any UI, feature, or page into a reusable component — and share it across your applications. It’s easier to collaborate and build faster.

Learn more

Split apps into components to make app development easier, and enjoy the best experience for the workflows you want:

Micro-Frontends

Design System

Code-Sharing and reuse

Monorepo

--

--

I am enthusiastic about programming, and marketing, and constantly seeking new experiences.