Oct 21, 2019

Explaining the benefits of using React Hooks like you're five - with examples


Since React.js reached the version 16.8 they introduce the use of Hooks. This was the alternative to enhance the functional components and having the same capabilities of the class components,which i write about a time ago.

First of all, What are React Hooks?

Hooks are a variety of functions, mostly pure, added to the React API that allow us to use all the stateful logic in the funtional components without change its structure.

The React team explained that they encountered several problems over some years maintaining ten of thousands components. They decide to create a new way of using the state and the lifecycles in components. You can read here the motivation.

So, here we show you how you can grasp the concept of Hooks. We'll see the most relevant and how you can migrate a class component easily.

useState

This is the most common and understandable Hooks, used as a homolgoc of this.state with few slightly difference. The useState is a function that receive the initial state of the component and return an array with two values, the first is the current state and the second the "setState" function of this state.

We've created a button component that change the color everytime we click it. we'll see the two ways, with class and after with hooks.

Class component
// Class component

class ButtonRandomColor extends Component {

  
  constructor(props) {
    super(props)
    
    // initializing the state in the constructor
    this.state = {
      currentColor: ""
    }
    // binding the "this" reference to this component. 
    // with hooks we avoid doing this.
    this.changeColor = this.changeColor.bind(this)
  }

  // Function to change the color of the state
  changeColor() {
    const letters = '0123456789ABCDEF';
    let color = '#';
    for (var i = 0; i < 6; i++) {
      color += letters[Math.floor(Math.random() * 16)];
    }
    this.setState({
      currentColor: color
    }) ;
  }

  // Render method
  render() {
    return (
      <button 
        onClick={this.changeColor}
        style={{
          backgroundColor: this.state.currentColor
        }}>
        Change My Color
      </button>
    )
  }
}
Functional component
function ButtonRandomColor () {
  const letters = '0123456789ABCDEF';
  // color is the current state and setColor is the function to change it. 
  // you can assign the name you want, this is possible thanks to destructuring 
  // part of the ES5 capabilities of javascript.
  const [color, setColor] = React.useState("") 

  // We declare the getRandomColor function as an arrow function.
  const getRandomColor = () => {
    let color = '#';
    for (var i = 0; i < 6; i++) {
      color += letters[Math.floor(Math.random() * 16)];
    }
    return color
  }

  // This is the template that will be rendered.
  return (
      <button 
        onClick={() => setColor(getRandomColor()) }
        style={{
          backgroundColor: color
        }}>
        Change My Color
      </button>
  )
} 
Differences and beneficts with hooks
  • We dont need to use the entire constructor method.
  • The state is not nessesary to be an object. Could be an primitive value (string, number, boolean).
  • We save a lot of typing without use "this"
  • The state aliases make the code more readable.
  • Look syntaticaly more simple.

useEffect

The useEffect hook come to show us how simple the life could be without the life-cycle methods. It allow you to perform side effects in function components. But what does it mean? it means all the operations that run before or after the render process.

It's commonly used with API request and asynchronous process. Let's take a look with an example.

Class component
class LyricViewer extends Component {

  // initializing the state in the constructor
  constructor(props) {
    super(props)
    this.state = {
      currentLyrics: ""
    }
    this.getLyric = this.getLyric.bind(this)
  }

  // Method to retrieve the data and save it in the state.
  async getLyric() {
    const { author, song } = this.props
    const res = await fetch(`https://api.lyrics.ovh/v1/{author}/{song}`)
    const response = await res.json()
    this.setState({
      currentLyrics: response.lyrics
    })
  }

  // Retrieves the data when the component is mounted.
  componentDidMount() {
    this.getLyric()
  }

  // It validates if the props has changed to call the componentDidUpdate method. 
  // It help to avoid unnecessary requests
  componentShouldUpdate(nextProps) {
    const { author, song } = this.props
    if (nextProps.author === author && nextProps.song === song) {
      return false
    }
    return true
  }

  // Retrieve the data again if the props change.
  componentDidUpdate() {
    this.getLyric()
  }

  // Render the lyrics
  render() {
    return (
      <div>
        {this.state.currentLyrics}
      </div>
    )
  }
}
Functional component
// Here, we're using destructuring to get
// just what we want of the props object passed as parameter.
function LyricViewer ({ author, song }) {
  const [lyrics, setLyrics] = React.useState("")

  const  getLyric = async () => {
    const res = await fetch(`https://api.lyrics.ovh/v1/{author}/{song}`)
    const response = await res.json()
    setLyrics(response.lyrics)
  }

  // Bellow is the important part of this snippet
  // This funciton will be called when our component is mounted
  // and/or some of these variables passed as second parameter in the array 
  // change their value.
  React.useEffect(() => {
    getLyric()
  },[author, song]) 
  // If author or song value change, the useEffect will run again.

  // Template
    return (
      <div>
        {lyrics}
      </div>
    )
} 
Differences and beneficts with hooks
  • We replace three methods just with one function.
  • This approach simplify the rendering process of the component.
  • useEffect evaluate itself when it should update (no componentShouldUpdate needed).
  • Almost the 60% of the code has been reduced.
  • Practically, the same beneficts of the past hook.

Others Hooks

Based in prevous hooks we cover here, the React team has implemented for us almost 8 hooks, we won't dig depper here but let's check some of the most relevant:

  • useContext: Receive a React's Conext Object and return the current context value.
  • useReducer: It's very similar to useState, but it use a reducer (like Redux) and the initial state to return the current state and the dispatcher function.
  • useCallback: It's useful when we need to memorize "high-weight" operations. Returns the memorized callback.
  • useRef: It returns a mutable object whose current property value is passed as argument.

Basically, these hooks have more advanced use, and might not be used frecuently. If you want read more about check the official react documentation.

So, Hooks worth it?

Totally yes, we kinda prove it above. At the beginnig is a little confusing forget about the "class" schema but i guarantee you that using them you can improve your productivity writing them more easyly.

This is the new approch is taking React, but we are not obligate to migrate all our existing app to hooks so it's good to stat using and prepare the new projects to the innovation of the library.

So, tell me. Do you already use Hooks? Comment bellow and share!

Explaining the benefits of using React Hooks like you're five - with examples
Commentarios