{{announcement.body}}
{{announcement.title}}

Introduction to React Hooks

DZone 's Guide to

Introduction to React Hooks

Get hooked on React hooks.

· Web Dev Zone ·
Free Resource

Image title

React hooks offer us a simplified interface to many React features. This intro will focus on using to access the state and lifecycle of a React component. Hooks are available in React version 16.8.0 or later. To check the version of React your app is running, reference your package.json.

We'll walk through the implementation of React hooks in a simple React app. This app will consume the very developer-friendly Hacker News API and display two views: Top Stories and New Stories. We're going to use two hooks in our app — useState and  useEffect. Hooks are intended to be used in function components; this app will only use function components.

The code for this app can be found in its entirety at https://github.com/josephemswiler/react-hooks-intro.

You may also like: Everything React: Tutorials for Beginners and Experts Alike.

useState

The wonderful useState hook allows us to read, update, and initialize states in function components. First, we import useState from React. Next, we use this hook on line six of App.js. How does it work? This line declares a new state variable, selectedand assigns it the value, "Top Stories". In class components, we could achieve similar functionality using this.state.

The last piece of the puzzle is setSelected. This is a function we can invoke to assign a new value to our state variable. In class components, we could achieve similar functionality using this.setState. We can see setSelected in action in the body of our handleClick function, which receives a value from the button components. When we pass a value to setSelected, it assigns that value to the related state variable (selected, in this case). That's it!

react-hooks-intro/src/App.js

import React, { useState } from "react";
import TopStories from "./TopStories";
import NewStories from "./NewStories";

export default () => {
  const [selected, setSelected] = useState("Top Stories");

  const handleClick = e => {
    const { innerText } = e.target;
    if (selected === innerText) {
      console.log(`�� ${innerText} is currently displayed.`);
      return null;
    }
    setSelected(innerText);
    console.log(`�� Now fetching ${innerText}...`);
  };

  const getComponent = () => {
    switch (selected) {
      case "Top Stories":
        return <TopStories />;
      case "New Stories":
        return <NewStories />;
      default:
        return null;
    }
  };

 return (
    <>
      <header className="header">
        {["Top Stories", "New Stories"].map(item => (
          <button
            key={item}
            className={selected === item ? "selected" : null}
            onClick={handleClick}
          >
            {item}
          </button>
        ))}
      </header>
      {getComponent()}
    </>
  );
};


useEffect

The useEffect hook allows us to leverage side effects in functional components. First, we import useEffect from React. Next, we use this hook inside our TopStories.js function component. To use this hook, we'll pass it two arguments: a function (including our side effect statements) and an empty array. In the function, we'll use a data fetching side effect to consume the HN API discussed above by defining and invoking getTopStories.

The empty array passed as the second argument tells React to only run the function passed as the first argument once, during the mounting lifecycle. In class components, we could achieve similar functionality using  componentDidMount. We'll discuss another way to use the second argument of useEffect below.

This effect doesn't necessarily require clean up, but if it did, we'd include that logic inside the body of the anonymous function on line 19 of TopStories.js. In class components, we could achieve similar functionality using componentWillUnmount. Notice that the mounting and unmounting lifecycles are coupled within this hook - this was intended to keep related logic grouped together.

react-hooks-intro/src/TopStories.js

import React, { useState, useEffect } from "react";
import Card from "./Card";

export default () => {
  const [storyIds, setStoryIds] = useState([]);
  const baseAPI = "https://hacker-news.firebaseio.com";
  const title = "Top Stories";

  useEffect(() => {
    console.log(`✅ ${title} mounting...`);

    const getTopStories = async () => {
      const res = await fetch(baseAPI + "/v0/topstories.json");
      const topStories = await res.json();
      setStoryIds(topStories.slice(0, 10));
    };
    getTopStories();

    return () => {
      console.log(`�� ${title} unmounting...`);
    };
  }, []);

  return (
    <section className="container">
      <h1>{title}</h1>
      {storyIds && storyIds.map(item => <Card key={item} id={item} />)}
    </section>
  );
};


As promised, we'll discuss the second argument passed to useEffect and how we can leverage this argument to use this hook in a different way. The array passed as the second argument can be used to conditionally run our useEffect hook. When we include a variable in this array, we ask React to listen for a change in the value assigned to that variable from the previous render.

In class components, we could achieve similar functionality using componentDidUpdate. In the useEffect hook in our Card.js component below, we pass [props.id] as the second argument and take advantage of this optimization by only running our hook when the value assigned to props.id differs from the previous render.

react-hooks-intro/src/Card.js

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

export default props => {
  const [story, setStory] = useState();
  const baseAPI = "https://hacker-news.firebaseio.com";

  const formatTime = unix => {
    const date = new Date(unix * 1000);
    return [date.getMonth(), date.getDate(), date.getFullYear()].join("/");
  };

  useEffect(() => {
    console.log(`�� Card ${props.id} updating...`);

    const getStory = async () => {
      const res = await fetch(baseAPI + `/v0/item/${props.id}.json`);
      const json = await res.json();
      setStory(json);
    };
    getStory();
  }, [props.id]);

  return story ? (
    <div className="card">
      <div className="row gutterBottom">
        <div>
          <a href={story.url} target="_blank" rel="noopener noreferrer">
            {story.title}
          </a>
        </div>
        <div className="details gutterLeft">{formatTime(story.time)}</div>
      </div>
      <div className="row details">
        <div>By: {story.by}</div>
      </div>
    </div>
  ) : (
    <div className="card">
      <div className="row gutterBottom">
        <div className="loading" />
      </div>
      <div className="row details loading" />
    </div>
  );
};


You made it! useState  and useEffect are two powerful hooks to add to your React skillset. Again, the code for this app can be found in its entirety at https://github.com/josephemswiler/react-hooks-intro. Feel free to extend this project or use it as an example to build your own app with hooks!

Go build something great!


Further Reading

Topics:
react hooks ,git ,git and github ,api ,application arguments ,arguments ,hooks api ,java

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}