React logo

React 16.8 – Captain Hook is here

React 16.8 was shipped on Feb 06, 2019, bringing with it the Hook feature that everyone was waiting for. It was a version behind schedule, as React 16.7 was going to be the one.

Captain Hook with binocular

Ok maybe not that Hook!!!

After over 6 months from its introduction in React Conf 2018, Facebook development team finally released Hook feature into a stable version release. This feature helps our functional components having most class components features, including having internal state, context, and even lifecycle methods!!!

Tl; dr;

React 16.8 shipped with the stable Hook feature, allowing us to use state, context and lifecycles inside functional components. Hooks resolves 3 problems that React had: Wrapper hell, Huge components, and Confusing classes. Facebook team advises that we should start using Hooks in our new React features for a consistent code style as well as reducing duplication.

Hooks overview

Hook is released without any breaking changes. It is a brand new feature and does not interfere with existing features.

Class components are hard to test, especially lifecycle methods. Using hooks can decouple the lifecycle functions and make them easy to test.

There are multiple kind of hooks: State Hook, Context Hook, Effect Hook, or build your own Custom Hooks.

Facebook has released a good documentation to Hooks here. In this post, we will just discuss about what I think is important to mention outside their documentation.

 

State Hook

More details here.

// what you see in their documents can be confusing
const [count, setCount] = useState(0);

// what it is actually is
const [state, setState] = useState(initialState);

Best thing about `useState` is that you can have multiple state control in your component. Traditionally, we only have 1 state object in a class component. But with this approach, we can have as many state objects as we need.

Context Hook

More details here.

// returns the value of the context
const value = useContext(SomeContext);

Nothing special here, calling `useContext` will return the value of that context, and instead of having to consume the context, we just need to use that value.

// traditional way of using context
render() {
  return (
    <Context.Consumer>
      {(value) => (<MyComponent value={value} />)}
    </ContextConsumer>
  );
}

// with useContext
const OtherComponent = () => {
  const value = useContext(Context);

  return (<MyComponent value={value} />);
};

 

Effect Hook

More details here.

Basically just an implementation of lifecycle methods. Every extra tasks that a component does besides rendering DOM elements are side effects, and should use effect Hook to execute them. I’ll use the same example in the documentation.

import React, { useState, useEffect } from 'react';

// class example
class Example extends React.Component {
  state = {
    count: 0,
  };

  componentDidMount() {
    // set title on mount
    document.title = `You clicked ${this.state.count} times`;
  }

  componentDidUpdate() {
    // set title on update
    document.title = `You clicked ${this.state.count} times`;
  }

  setCount = (count) => {
    this.setState({ coount });
  };

  render() {
    const { count } = this.state;
    return (
      <div>
        <p>You clicked {count} times</p>
        <button onClick={() => this.setCount(count + 1)}>
          Click me
        </button>
      </div>
    );
  }
}

// functional example
function Example() {
  const [count, setCount] = useState(0);

  // Similar to componentDidMount and componentDidUpdate:
  useEffect(() => {
    // Update the document title using the browser API
    document.title = `You clicked ${count} times`;
  });

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

We can clearly see that the code is duplicated on `componentDidMount()` and `componentDidUpdate()` lifecycle functions. Effect Hook helps us removing that duplication.

Custom Hooks

More details here.

Something to remember here, React will consider a function to be a custom Hook if it starts with use.

useTitleUpdate = (count) => {
  document.title = `You clicked ${count} times`;
};

// usage
const MyComponent = () => {
  const [count, setCount] = useState(0);
  useTitleUpdate(count);

  return (...);
};

Important thing to remember

– Hooks are only declared at top level, meaning we CANNOT declare Hooks in the following examples.

// loops
for (let i = 0; i < 10; i++) {
  const [value, setState] = useState(1);
  ...
}

// conditions
if (x === 1) {
  const [value, setState] = useState(1);
  ...
}

// nested functions
const MyComponent = () => {
  const handleSave = () => {
    const [value, setState] = useState(1);
    ...
  };
};

There is a linter plugin to prevent developers doing this.

Other releases

Along with Hooks, React 16.8 also releases bug fixes and test utilities to test Hooks feature.

 

Quick recap

Hooks feature certainly offers a way to make React code more readable and efficient. However, we do not need to change the existing class components to use Hooks, as suggested in their talk at React Conference 2018. Both of them are doing the same thing under the hood, it’s just the implementation that is different.

2 thoughts to “React 16.8 – Captain Hook is here”

Leave a Reply

Your email address will not be published. Required fields are marked *