React Hooks
Classes, Function Components, and Hooks
It is very common to see a React component written like this:
import React, { Component } from 'react'
export default class Component extends Component {
state = {
active: false,
loading: true
}
componentDidMount() {
mockApi().then(() => {
this.setState({
loading: false
})
})
}
toggle() {
this.setState({
active: !this.state.active
})
}
render() {
if (this.state.loading) {
return 'loading...'
}
return (
<p onClick={this.toggle.bind(this)}>
{this.state.active ? 'hello' : 'goodbye'}
</p>
)
}
}
This is a component writted as a class. Classes have state that we can store and update. They also have lifecycle methods that we can hook into.
Making presentational components
Over time certain UI elements start to become reused throughout your app. It is common to make a components folder for very simple components that only worry about style and recieved state from props. For this, a class is a bit overkill:
import React, { Component } from 'react'
export default class Component extends Component {
render() {
return <p>{props.text}</p>
}
}
We can instead just export a function:
import React from 'react'
export default props => <p>{props.text}</p>
Hooks
FP (Functional Programing) and OOP(Object Oriented Programming) are 2 styles of programming. Classes feel very familiar to those with an OOP background. But for those who want to take a more FP approach, a library called Recompose was built to make small composable elements. Andrew Clark, one of its maintainers has since joined the React team and has worked on React Hooks, which solves many of the problems recompose originally tried to solve. So if you lean more towards FP, React Hooks is a good tool to use.
Comparing Hooks and Classes
Click Handlers
With a Class Component:
import React, { Component } from 'react'
export default class Component extends Component {
state = {
active: false
}
toggle = () => {
this.setState({
active: !this.state.active
})
}
render() {
return (
<p onClick={this.toggle}>
{this.state.active ? 'hello' : 'goodbye'}
</p>
)
}
}
With Hooks:
import React, { useState } from 'react'
export default () => {
const [active, updateActive] = useState(false)
const toggle = () => updateActive(!active)
return <p onClick={toggle}>{active ? 'hello' : 'goodbye'}</p>
}
Data Fetching on initial render
With a Class Component:
import React, { Component } from 'react'
export default class Component extends Component {
state = {
loading: true
}
componentDidMount() {
mockApi().then(() => {
this.setState({
loading: false
})
})
}
render() {
if (this.state.loading) {
return 'loading...'
}
return <p>hello</p>
}
}
With Hooks:
import React, { useEffect } from 'react'
export default () => {
const [loading, updateLoading] = useState(true)
useEffect(() => {
mockApi().then(() => {
updateLoading(false)
})
}, [])
if (loading) {
return 'loading...'
}
return <p>hello</p>
}