DEV Community

loading...

React Hooks

huyddo profile image Huy Do ・5 min read

React Hooks

Hooks are a new addition in React 16.8. They let you use state and other React features without writing a class

import React, { useState } from 'react';

function Example() {
  // Declare a new state variable, which we'll call "count"
  const [count, setCount] = useState(0);

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

It’s hard to reuse stateful logic between components

React doesn’t offer a way to “attach” reusable behavior to a component (for example, connecting it to a store). If you’ve worked with React for a while, you may be familiar with patterns like render props and higher-order components that try to solve this. But these patterns require you to restructure your components when you use them, which can be cumbersome and make code harder to follow. If you look at a typical React application in React DevTools, you will likely find a “wrapper hell” of components surrounded by layers of providers, consumers, higher-order components, render props, and other abstractions. While we could filter them out in DevTools, this points to a deeper underlying problem: React needs a better primitive for sharing stateful logic.

With Hooks, you can extract stateful logic from a component so it can be tested independently and reused. Hooks allow you to reuse stateful logic without changing your component hierarchy. This makes it easy to share Hooks among many components or with the community.

Complex components become hard to understand
We’ve often had to maintain components that started out simple but grew into an unmanageable mess of stateful logic and side effects. Each lifecycle method often contains a mix of unrelated logic. For example, components might perform some data fetching in componentDidMount and componentDidUpdate. However, the same componentDidMount method might also contain some unrelated logic that sets up event listeners, with cleanup performed in componentWillUnmount. Mutually related code that changes together gets split apart, but completely unrelated code ends up combined in a single method. This makes it too easy to introduce bugs and inconsistencies.

To solve this, Hooks let you split one component into smaller functions based on what pieces are related (such as setting up a subscription or fetching data), rather than forcing a split based on lifecycle methods. You may also opt into managing the component’s local state with a reducer to make it more predictable.

Classes confuse both people and machines
In addition to making code reuse and code organization more difficult, we’ve found that classes can be a large barrier to learning React. You have to understand how this works in JavaScript, which is very different from how it works in most languages. You have to remember to bind the event handlers. Without unstable syntax proposals, the code is very verbose. People can understand props, state, and top-down data flow perfectly well but still struggle with classes. The distinction between function and class components in React and when to use each one leads to disagreements even between experienced React developers.

To solve these problems, Hooks let you use more of React’s features without classes. Conceptually, React components have always been closer to functions. Hooks embrace functions, but without sacrificing the practical spirit of React. Hooks provide access to imperative escape hatches and don’t require you to learn complex functional or reactive programming techniques.

The above code use useState is a Hook. It's called inside the function component and we added some local state to it. React will reserve this state between re-dender.
useState return pair (the current state value and a function that let you update it) such as 0 and setCount(). We can call this function from event handler. It's similar to this.setState in class, but it doesn't merge old the old and new state together.

Hooks are functions that let you "hook into"React state and lifecycle features from function components. Hooks don't work in classes. They let you use react without classes.

Effect Hook

Effect Hook when we are fetching data, subscriptions, or change DOM from React components. These operations can effect other components and can't be done during rendering
The Effect Hook useEffect which adds the ability to perform side effects from a function component. It serves the same purpose as componentDidMount, componentDidUpdate, componentWillUnmount in React classes, but unified into a single API

In the example below, the component sets the document title after React updates the DOM. Effect function will run after flushing changes to the DOM. The Effect function was declared inside the component, so it has access its props and states. React run the effects after every render (including the first render).

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

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

Effects can clean up after them by returning a function. For example, this component use an effect to subscribe to a friend's online status and cleans up by unsubscribing from it. In this example, React would unsubscribe from our ChatAPI when the component unmounts, as well as before re-running the effect due to a subsequent render. (If you want, there’s a way to tell React to skip re-subscribing if the props.friend.id we passed to ChatAPI didn’t change.)

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

function FriendStatus(props) {
  const [isOnline, setIsOnline] = useState(null);

  function handleStatusChange(status) {
    setIsOnline(status.isOnline);
  }

  useEffect(() => {
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });

  if (isOnline === null) {
    return 'Loading...';
  }
  return isOnline ? 'Online' : 'Offline';
}
Enter fullscreen mode Exit fullscreen mode

Rules of Hooks
Only call Hooks at the top level. Don’t call Hooks inside loops, conditions, or nested functions.

Only call Hooks from React function components. Don’t call Hooks from regular JavaScript functions.

Building Your Own Hooks
We can resue some stateful logic between components by creating custom Hooks instead of using higher-order components HOC and render props. We can use FriendStatus component that calls the useState and useEffect by using the useFriendStatus with friendID argument and return whenever our friend is online.

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

function useFriendStatus(friendID) {
  const [isOnline, setIsOnline] = useState(null);

  function handleStatusChange(status) {
    setIsOnline(status.isOnline);
  }

  useEffect(() => {
    ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
    };
  });

  return isOnline;
}
Enter fullscreen mode Exit fullscreen mode

Now you can use it from both components.

function FriendStatus(props) {
  const isOnline = useFriendStatus(props.friend.id);

  if (isOnline === null) {
    return 'Loading...';
  }
  return isOnline ? 'Online' : 'Offline';
}
Enter fullscreen mode Exit fullscreen mode
function FriendListItem(props) {
  const isOnline = useFriendStatus(props.friend.id);

  return (
    <li style=`{{` color: isOnline ? 'green' : 'black' }}>
      {props.friend.name}
    </li>
  );
}
Enter fullscreen mode Exit fullscreen mode

The state of these components is complete independent. Hooks reuse stateful logic not stat itself. Thus, you can use the same custom Hook twice in one component.

The convention of custom Hooks is adding use in front of the function name.

References
https://reactjs.org/docs/hooks-intro.html
https://reactjs.org/docs/hooks-overview.html

Discussion (0)

pic
Editor guide