How to convert a React Class Component to a Function Component
Tags: react, javascript, webdev, tutorial
Published: 2020-04-17 01:53:27

---
title: How to convert a React Class Component to a Function Component
published: true
date: 
tags: react, javascript, webdev, tutorial
canonical_url: https://nimblewebdeveloper.com/blog/convert-react-class-to-function-component
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/9q372ky7u2f7rekwv2by.png
---

Since the React 16.8 update which added hooks to function components, you might have seen function components replacing class components everywhere.

Partly this is just because developers suffer from 'shiny-object-syndrome', and hooks are new and shiny, but there are also good reasons for the shift as well.

Function components are _far_ less verbose, and require less boilerplate. They're (in my opinion) a bit more flexible with hooks and custom hooks, and they are (usually) a bit more performant.

## What's the difference between class components and function components?

Well to put it simply, one is a class, and the other is... a function!

Take these examples below. The first one is a class component, the second one is a function component. They both do exactly the same thing.

```jsx  
// Example class component  
  
class MyComponent extends React.Component {  
    
  render() {  
    return <p>Hello, {this.props.name}    
  }  
    
}  
  
  
//Example function component  
  
function MyComponent(props) {  
  return <p>Hello, {props.name}</p>  
}  
  
```

Both components take a prop (name) and render `Hello, **{name}** `. It's an extremely simple example but already we can see some of the differences.

The class component needs to extend the React **Component** class, and must specify a **render** method. Whereas the function component is simply a function, and the render method is simply the return value of the function.

## Why convert a class component to a function component

If you've got a slightly older codebase, and you'd like to refactor some of your components into function components, then you're in the right place!

**_Beware!_** Not all class components can be converted to functions! There are still some cases where you need to use a class component. But 99% of the time you'll be fine with a function component.

## When can't you use a function component?

There are some use cases where a function component simply won't work. We'll quickly discuss a couple, and there may be more! Consider yourself warned.

#### If you _need_ a constructor

If you really, _really_ need a constructor, you're gonna have a bad time. A constructor runs **once** and only exactly **once** , before the first render of the component. Currently, I haven't found a hook that will replace this functionality (know of one? [Let me know!](https://twitter.com/baffledbasti))

Most of the time all that's being done in the constructor of a class component anyway is setting up state, and binding event listeners. Both these things are handled differently in function components so we're good.

#### If you need to extend a component

In Javascript, classes can extend other classes, thus inheriting the parent's prototype. In fact, if you're creating a class component, you _have_ to extend the base component from React. This is more or less not possible with function components, so I wouldn't bother trying

#### Higher order components

You can make a HOC (higher order component) with a function, however it can often be a bit easier to use a class. Up to you, just be warned.

#### Side-effects of combined state updates

this.setState is no longer available in a function component. Instead we use the **useState** hook, which returns a state variable, and an updater function. If you have some peculiar pattern where you're updating a couple of state variables at once, and need to run a specific side effect, you might find this difficult (not impossible) with a function component.

As an example, if you do this

```jsx  
class MyComponent extends React.Component {  
    
  onSomeEventHandler(newName) {  
      
    this.setState({  
      counter: this.state.counter+1,  
      name: newName  
    }, () => {  
      console.log('Counter AND name have been updated!')  
    })  
      
  }  
     
}  
  
```

You're going to struggle to exactly replicate that functionality with a function component.

## Quick steps to convert to a function component

### 1. Change the class to a function

Change

```jsx  
class MyComponent extends React.Component {  
  //...  
}  
  
```

to

```jsx  
function MyComponent(props) {  
  //...  
}  
  
```

### 2. Remove the render method

Remove the render method, but keep everything after & including the **return**. Make this the last statement in your function.

From

```jsx  
//...  
  render() {  
      
    return (<p>Hello, World</p>);  
    
  }  
//...  
  
```

To

```jsx  
function MyComponent(props) {  
  //...  
  
  return (<p>Hello, World</p>);  
    
} // end of function  
  
```

### 3. Convert all methods to functions

Class methods won't work inside a function, so lets convert them all to functions (closures).

From

```jsx  
class MyComponent extends React.Component {  
    
  onClickHandler(e) {  
    // ...  
  }  
    
}  
  
jsx  
function MyComponent {  
    
  const onClickHandler = (e) => {  
    //...  
  }  
    
}  
  
```

### 4. Remove references to _this_

The this variable in your function isn't going to be super useful any more. Remove the references to it throughout your render and functions.

Change

```jsx  
clas MyComponent(props) extends React.Component {  
    
  //...  
    
  mySpecialFunction() {  
    console.log('you clicked the button!')  
  }  
    
  onClickHandler(e) {  
    this.mySpecialFunction();  
  }  
    
    
  render() {  
    return (  
      <div>  
        <p>Hello, {this.props.name}</p>  
        <button onClick={this.onClickHandler}>Click me!</button>  
      </div>  
    );  
  }  
    
}  
  
```

To

```jsx  
function MyComponent(props) {  
    
  //...  
    
  const mySpecialFunction = () => {  
    console.log('you clicked the button!')  
  }  
    
  const onClickHandler = (e) => {  
    mySpecialFunction();  
  }  
    
  return (  
    <div>  
      <p>Hello, {props.name}</p>  
      <button onClick={onClickHandler}>Click me!</button>  
    </div>  
  );  
    
}  
  
```

### 5. Remove constructor

Simply removing the constructor is a little tricky, so I'l break it down further.

#### 1. useState

Instead of

```jsx  
constructor(props) {  
  super(props);  
  //Set initial state  
  this.state = {  
    counter: 0,  
    name: ""  
  }  
}  
  
```

Use the useState hook

```jsx  
function MyComponent(props) {  
    
  const [counter,setCounter] = useState(0);  
  const [name,setName] = useState("");  
    
}  
  
```

#### 2. Remove event handler bindings

We don't need to bind event handlers any more with function components. So if you were doing this;

```jsx  
constructor(props) {  
  this.onClickHandler = this.onClickHandler.bind(this);  
}  
  
```

You can simply remove these lines. (What a gross, overly verbose syntax anyway).

### 6. Replace this.setState

this.setState obviously doesn't exist any more in our function component. Instead we need to replace each of our setState calls with the relevant state variable setter.

Replace this;

```jsx  
class MyComponent extends React.Component {  
    
  onClickHandler(e) {  
    this.setState({count: this.state.count+1})  
  }  
    
}  
  
```

With this;

```jsx  
function MyComonent {  
    
  const [count, setCount] = useState(0)  
    
  const onClickHandler = e => {  
      
    setCount(count+1);  
      
  }  
    
}  
  
```

### 7. useEffect for state update side effects

Remember how this.setState could accept a callback that would run after the state was updated? Well our useState updater function does no such thing. Instead we have to use the useEffect hook. It doesn't work exactly the same though! useEffect will trigger whenever and of it's dependencies are changed.

If you do this;

```jsx  
this.setState({counter: this.state.counter+1}, () => {  
  console.log('Counter was updated!')  
})  
  
```

Do this instead

```jsx  
const [counter, setCounter] = useState(0)  
  
useEffect(() => {  
  console.log('counter changed!')  
}, [counter])  
  
```

### 8. Replace lifecycle methods with hooks

#### ComponentDidMount

Instead of using the componentDidMount method, use the useEffect hook with an empty dependency array.

```jsx  
useEffect(()=>{  
  console.log('component mounted!')  
},[]) //notice the empty array here  
  
```

#### ComponentWillUnmount

Instead of using the componentWillUnmount method to do cleanup before a component is removed from the React tree, return a function from the useEffect hook with an empty dependency array;

```jsx  
useEffect(() => {  
  console.log('component mounted')  
    
  // return a function to execute at unmount  
  return () => {  
    console.log('component will unmount')  
  }  
}, []) // notice the empty array  
  
```

#### ComponentDidUpdate

If you pass nothing as the second argument to useEffect, it will trigger whenever a component is updated. So instead of using componentDidUpdate, use;

```jsx  
useEffect(() => {  
    
  console.log('component updated!')  
    
}) // notice, no second argument  
  
```

## Example components converted to functions

### Example 1 - simple state

Replace this

```jsx  
import React, {Component} from 'react';  
  
class MyComponent extends Component {  
    
  constructor(props) {  
      
    super(props);  
      
    this.state = {  
      count: props.count || 0  
    }  
      
    this.onClickHandler = this.onClickHandler.bind(this);  
      
  }  
    
  onClickHandler(e) {  
      
    this.setState({  
      count: this.state.count + 1;  
    })  
      
  }  
    
  render() {  
    return (  
      <div>Count : {this.state.count}</p>  
          <p>Count isis: {this.state.count}</p>  
        <button onClick={onClickHandler}>Increase Count</button>  
      </div>  
    );  
  }  
}  
  
```

With this

```jsx  
import, React {useState} from 'react';  
  
function MyComponent(props) {  
    
  const [count, setCount] = useState(props.count || 0);  
    
  const onClickHandler = () => {  
    setCount(count + 1);  
  }  
    
  return (  
    <div>  
      <p>Count is: {count}</p>  
      <button onClick={onClickHandler}>Increase count</button>  
    </div>  
  );  
  
}  
  
```

### Example 2 - useEffect

Replace this

```jsx  
import React, {Component} from 'react';  
  
class MyComponent extends Component {  
    
  constructor(props) {  
      
    super(props);  
      
    this.state = {  
      data: null,  
      isLoading: false,  
      error: null  
    }  
      
  }  
    
  async loadAsyncData() {  
      
    this.setState({isLoading: true, error: null});  
      
    try {  
      const resp = await fetch('https://...').then(r=>r.json());  
      this.setState({isLoading: false, data: resp});  
    } catch(e) {  
      this.setState({isLoading: false, error: e});  
    }  
      
  }  
    
  componentDidMount() {  
      
    loadAsyncData();  
      
  }  
    
  render() {  
      
    if(this.state.isLoading) return (<p>Loading...</p>);  
    if(this.state.error) return (<p>Something went wrong</p>);  
    if(this.state.data) return (<p>The data is: {data}</p>);  
    return (<p>No data yet</p>);  
      
  }  
}  
  
```

With this

```jsx  
import React, {useEffect, useState} from 'react';  
  
function MyComponent() {  
    
  const [data, setData] = useState();  
  const [isLoading, setIsLoading] = useState(false);  
  const [error, setError] = useState();  
    
  const loadAsyncData = async () => {  
    
    setIsLoading(true);  
    setError(null);  
      
    try {  
      const resp = await fetch('https://...').then(r=>r.json());  
      setData(resp);  
      setIsLoading(false);  
    } catch(e) {  
      setError(e);  
      setIsLoading(false);  
    }  
      
  }  
    
  useEffect(() => {  
      
    loadAsyncData();  
      
  }, []);  
    
      
  if(this.state.isLoading) return (<p>Loading...</p>);  
  if(this.state.error) return (<p>Something went wrong</p>);  
  if(this.state.data) return (<p>The data is: {data}</p>);  
  return (<p>No data yet</p>);  
      
}  
  
```