- Published on
Converting React Class Component to Functional Hooks Component
- Authors
- Name
- Yair Mark
- @yairmark
Today I had to convert a class style React component to the functional hook based one. Initially it was a bit tricky but after converting one it became super easy for others. I really dig the functional approach as you can drop a lot of the frivalous cruft you have to usually add when working with classes for example with the functional approahc:
- No need for
this
: There is no need to keep addingthis.someFunction = this.someFunction.bind(this)
to the constructor to make sure you are using the same this in the class method- Just be sure to define inner methods as arrow functions (
const myMethod = () => {}
) instead of normal functions (myMethod() {}
) as this will ensure you use the samethis
as the wrapping component function.
- Just be sure to define inner methods as arrow functions (
- Much less verbose: Far less verbose as you do not need to keep referring to
this.prop.foo
orthis.state.bar
instead you simply refer to them asfoo
andbar
respectively. - Props all declared in one place: Props are more readable as you can see the destructured props in one place at the top of your functional component instead of having to find all
this.props
in your class to find all props.- You also do not need to keep destructuring
this.props
if you normally prefer destructuring them where you use them for readability.
- You also do not need to keep destructuring
Below I provide an example of a class style component and the equivalent functional version as well as a mini cheat sheet for how to convert from the class based approach to the functional approach.
Original Class Style React Component
import React, { Component } from 'react'
class MyComponent extends React.Component {
constructor(props) {
super(props)
this.state = {
name: '',
surname: '',
}
this.someClassMethod = this.someClassMethod.bind(this)
}
componentWillMount() {
//do foo
}
componentWillUnmount() {
//do bar
}
someClassMethod() {
//does something
this.setState({ name: 'Bill' })
}
render() {
return (
<div>
{' '}
Hi {this.state.name} {this.state.surname} {this.props.emoji} {this.props.someOtherProp}{' '}
</div>
)
}
}
export default MyComponent
React 16 Functional Hook Style Component
import React, { useEffect, useState } from 'react'
function MyComponent({ emoji, someOtherProp }) {
const [name, setName] = useState('')
const [surname, setSurname] = useState('')
useEffect(() => {
//do foo
return () => {
// do bar
}
}, [])
const someClassMethod = () => {
//does something
setName('Bill')
}
return (
<div>
{' '}
Hi {name} {surname} {emoji} {someOtherProp}{' '}
</div>
)
}
export default MyComponent
When using the useState
hook to work with state you can refer to the previous state of something. For example for name
this would be done as follows: setName(previousName => previousName + name);
. In this example the new name is concatenated with the existing name.
Mini Cheatsheet
Based on my current understanding and experience moving an existing class based component to the functional hooks based approach my cheatsheet would look as follows:
React Class Component | React Functional Hooks Component |
---|---|
import React, { Component } from "react"; | import React, { useEffect, useState } from "react"; |
class MyComponent extends React.Component { | function MyComponent({ emoji, someOtherProp }) { |
constructor(props){ | Not needed - anything you need to initialize for later just put as let s or const s just after the { where you defined your component |
this.state = { name: ""}; | const [name, setName] = useState(""); |
this.someClassMethod = this.someClassMethod.bind(this); | No need, this is the same as long as you use arrow functions (=> ) to define your methods inside the functional component |
componentWillMount() { /*foo*/} | useEffect(() => {/*foo*/},[]) note the [] at the end which are needed to make this run once |
componentWillUnmount() { /*bar*/} | useEffect(() => { return () => {/*bar*/}},[]) note the [] at the end which are needed to make this run once |
componentWillMount() { /*foo*/} ... componentWillUnmount(){ /*bar*/} | useEffect(() => {/*foo*/ return () => {/*bar*/}},[]) note the [] at the end which are needed to make this run once |
someClassMethod() { | const someClassMethod = () => { |
this.setState({name: 'Bill'}); | setName('bill') where you defined const [name, setName]= useState("") higher up |
render(){ return (<div> Hello </div>); | return (<div> Hello </div>); |
this.someprop | function yourComponent({someprop}) { ... someprop You simply refer to prop that was destructured in your functional component definition |