Fetching data using React.js

We used the native fetch API supported by most browsers to perform an asynchronous request to an API. We’re prepared to fetch data from the Hacker News API. There was one lifecycle method mentioned that can be used to fetch data: `componentDidMount()`.

Key points

#N1
Development team

Fetching data using React.js

Fetching Data

We’re prepared to fetch data from the Hacker News API. There was one lifecycle method mentioned that can be used to fetch data: `componentDidMount()`. Before we use it, let’s set up the URL constants and default parameters to break the URL endpoint for the API request into smaller pieces.

src/App.js

import React, { Component } from 'react';
import './App.css';
const DEFAULT_QUERY = 'redux';
const PATH_BASE = 'https://hn.algolia.com/api/v1';
const PATH_SEARCH = '/search';
const PARAM_SEARCH = 'query=';

...

In JavaScript ES6, you can use template literals for string concatenation or interpolation. You will use it to concatenate your URL for the API endpoint.

Code Playground

// ES6
const url = `${PATH_BASE}${PATH_SEARCH}?${PARAM_SEARCH}${DEFAULT_QUERY}`;
// ES5
var url = PATH_BASE + PATH_SEARCH + '?' + PARAM_SEARCH + DEFAULT_QUERY;
console.log(url);
// output: https://hn.algolia.com/api/v1/search?query=redux

This will keep your URL composition flexible in the future. Below, the entire data fetch process will be presented, and each step will be explained afterward.

src/App.js

...
class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      result: null,
      searchTerm: DEFAULT_QUERY,
    };
    this.setSearchTopStories = this.setSearchTopStories.bind(this);
    this.onSearchChange = this.onSearchChange.bind(this);
    this.onDismiss = this.onDismiss.bind(this);
  }
  setSearchTopStories(result) {
    this.setState({ result });
  }

  componentDidMount() {
    const { searchTerm } = this.state;
    fetch(`${PATH_BASE}${PATH_SEARCH}?${PARAM_SEARCH}${searchTerm}`)
      .then(response => response.json())
      .then(result => this.setSearchTopStories(result))
      .catch(error => error);
  }
  ...
}

First, we will return a real list from the Hacker News API, so the sample data is no longer used. The initial state of your component has an empty result and default search term now. The same default search term is used in the input field of the Search component, and in your first request.

Second, you use the componentDidMount() lifecycle method to fetch the data after the component mounted. The first fetch uses default search term from the local state. It will fetch “redux” related stories, because that is the default parameter

Third, the native fetch API is used. The JavaScript ES6 template strings allow it to compose the URL with the searchTerm. The URL is the argument for the native fetch API function. The response is transformed to a JSON data structure, a mandatory step in a native fetch with JSON data structures, after which it can be set as result in the local component state. If an error occurs during the request, the function will run into the catch block instead of the then block. Last, remember to bind your new component method in the constructor. You can output the local state with console.log(this.state); in your render() method to visualize it. In the next step, we use the result to render it. But we will prevent it from rendering anything, so we will return null, when there is no result in the first place. Once the request to the API has succeeded, the result is saved to the state and the App component will re-render with the updated state.

src/App.js

class App extends Component {

    ...
  render() {
    const { searchTerm, result } = this.state;
  
    if (!result) { return null; }
    
    return (
      <div className="page">
        ...
        <Table
          list={result.hits}
          pattern={searchTerm}
          onDismiss={this.onDismiss}
        />
      </div>
    );
  }
}

Now, let’s recap what happens during the component lifecycle. Your component is initialized by the constructor, after which it renders for the first time. We prevented it from displaying anything, because the result in the local state is null. It is allowed to return null for a component to display nothing. Then the componentDidMount() lifecycle method fetches the data from the Hacker News API asynchronously. Once the data arrives, it changes your local component state in setSearchTopStories(). The update lifecycle activates because the local state was updated. The component runs the render() method again, but this time with populated result in your local component state. The component and the Table component will be rendered with its content.

We used the native fetch API supported by most browsers to perform an asynchronous request to an API. The create-react-app configuration makes sure it is supported by all browsers. There are also third-party node packages that you can use to substitute the native fetch API: axios.

In the example, if (!result) was used in favor of if (result === null). The same applies for other cases as well. For instance, if (!list.length) is used in favor of if (list.length === 0) or if (someString) is used in favor of if (someString !== '').

Completely Example

src/App.js

import React, { Component } from 'react';
import './App.css';
import Search from './Search.js';
import Table from './Table.js';
const DEFAULT_QUERY = 'redux';
const PATH_BASE = 'https://hn.algolia.com/api/v1';
const PATH_SEARCH = '/search';
const PARAM_SEARCH = 'query=';

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      result: null,
      searchTerm: DEFAULT_QUERY,
    };
    this.setSearchTopStories = this.setSearchTopStories.bind(this);
    this.onSearchChange = this.onSearchChange.bind(this);
    this.onDismiss = this.onDismiss.bind(this);
  }
  setSearchTopStories(result) {
    this.setState({ result });
  }

  onSearchChange(event) {
    this.setState({ searchTerm: event.target.value });
    this.fetchData(); 

    
  }

  onDismiss(id) {
    const isNotId = item => item.objectID !== id;
    const updatedHits = this.state.result.hits.filter(isNotId);
    this.setState({
    result: Object.assign({}, this.state.result, { hits: updatedHits })
    });
  }

  fetchData(){
    const { searchTerm } = this.state;
    fetch(`${PATH_BASE}${PATH_SEARCH}?${PARAM_SEARCH}${searchTerm}`)
      .then(response => response.json())
      .then(result => this.setSearchTopStories(result))
      .catch(error => error);
  }

  componentDidMount() {
    // const { searchTerm } = this.state;
    // fetch(`${PATH_BASE}${PATH_SEARCH}?${PARAM_SEARCH}${searchTerm}`)
    //   .then(response => response.json())
    //   .then(result => this.setSearchTopStories(result))
    //   .catch(error => error);
    this.fetchData(); 
  }
  render() {
    const { searchTerm, result } = this.state;
  
    if (!result) { return null; }
    
    return (
      <div className="page">
        <Search
          value={searchTerm}
          onChange={this.onSearchChange}
        />

        <Table
          list={result.hits}
          pattern={searchTerm}
          onDismiss={this.onDismiss}
        />
      </div>
    );
  }
}

export default App;

src/Search.js

import React, { Component } from 'react';

class Search extends Component {
  render() {
    const { value, onChange } = this.props;
    return (
      <form>
        <input
          type="text"
          value={value}
          onChange={onChange}
        />
      </form>
    );
  }
}

export default Search; 

src/Button.js

import React, { Component } from 'react';

class Button extends Component {
  render() {
    const {
      onClick,
      className,
      children,
    } = this.props;

    return (
      <button
        onClick={onClick}
        className={className}
        type="button"
      >
      {children}
      </button>
    );
  }
}

export default Button;

src/Table.js

import React, { Component } from 'react';
import Button from './Button.js';

class Table extends Component {
  render() {
    const { list, pattern, onDismiss } = this.props;
    return (
      <div>
        {list.map(item =>
          <div key={item.objectID}>
            <span>
              <a href={item.url}>{item.title}</a>
            </span>
            <span>{item.author}</span>
            <span>{item.num_comments}</span>
            <span>{item.points}</span>
            <span>
              <Button onClick={() => onDismiss(item.objectID)}>
                Dismiss
              </Button>
            </span>
          </div>
        )}
      </div>
    );
  }
}

export default Table;

Output :

#N2
Development team

Installation

Installation

There are many approaches to getting started with a React application. The first we’ll explore is a CDN, short for content delivery network. Many companies use CDNs to host files publicly for their consumers. Some of these files are libraries like React, since the bundled React library is just a react.js JavaScript file. To get started with React by using a CDN, find the <script> tag in your web page HTML that points to a CDN url.

You will need two libraries: react and react-dom.

Code Playground

<script crossorigin
        src="https://unpkg.com/react@16/umd/react.development.js"
></script>
<script crossorigin
        src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"
></script>

You can also get React into your application by initializing it as node project. With a package.json file, you can install react and react-dom from the command line. However, the folder must be initialized as a npm project using npm init -y with a package.json file. You can install multiple node packages with npm:

Command Line

npm install react react-dom

This approach is often used to add React to an existing application managed with npm. You may also have to deal with Babel to make your application aware of JSX (the React syntax) and JavaScript ES6. Babel transpiles your code–that is, it converts it to vanilla JavaScript–so most modern browsers can interpret JavaScript ES6 and JSX. Because of this difficult setup, Facebook introduced create-react-app as a zero-configuration React solution. The next section will show you how to setup your application using this bootstrapping tool.

Zero-Configuration Setup

we can use create-react-app to bootstrap your application. It’s an opinionated yet zero-configuration starter kit for React introduced by Facebook in 2016, recommended for beginners by 96% of React users. In create-react-app the tooling and configuration evolve in the background, while the focus is on the application implementation.

To get started, install the package to your global node packages, which keeps it available on the command line to bootstrap new React applications:

Command Line

npm install -g create-react-app

You can check the version of create-react-app to verify a successful installation on your command line:

Command Line

create-react-app --version
*v5.0.1

Now you are ready to bootstrap your first React application. The example will be referred to as hackernews, but you may choose any name you like. First, navigate into the folder:

Command Line

create-react-app hackernews
cd hackernews
npm install react react-dom

Now you can open the application in your editor. The following folder structure, or a variation of it depending on the create-react-app version, should be presented to you:

Folder Structure

hackernews/
    README.md
    node_modules/
    package.json
    .gitignore
    public/
      favicon.ico
      index.html
      manifest.json 

    src/
      App.css
      App.js
      App.test.js
      index.css
      index.js
      logo.svg
      serviceWorker.js

This is a breakdown of the folders and files:

  • README.md: The .md extension indicates the file is a markdown file. Markdown is used as a lightweight markup language with plain text formatting syntax. Many source code projects come with a README.md file to give you initial instructions about the project. When pushing your project to a platform such as GitHub, the README.md file usually displays information about the content contained in the repository. Because you used create-react-app, your README.md should be the same as the official create-react-app GitHub repository⁴⁹.

  • node_modules/: This folder contains all node packages that have been installed via npm. Since you used create-react-app, there should already be a couple of node modules installed for you. You will rarely touch this folder, because node packages are generally installed and uninstalled with npm from the command line.

  • package.json: This file shows you a list of node package dependencies and other project configurations.

  • .gitignore: This file displays all files and folders that shouldn’t be added to your git repository when using git; such files and folders should only be located in your local project. The node_- modules/ folder is one example. It is enough to share the package.json file with others, so they can install dependencies on their end with npm install without your dependency folder.

  • public/: This folder holds development files, such as public/index.html. The index is displayed on localhost:3000 when developing your app. The boilerplate takes care of relating this index with all the scripts in src/.

  • build/ This folder is created when you build the project for production, as it holds all of the production files. When building your project for production, all the source code in the src/ and public/ folders are bundled and placed in the build folder.

  • manifest.json and serviceWorker.js: These files won’t be used for this project, so you can ignore them for now.

In the beginning, everything you need is located in the src/ folder. The main focus lies on the src/App.js file which is used to implement React components. It will be used to implement your application, but later you might want to split up your components into multiple files, where each file maintains one or more components on its own.

Additionally, you will find a src/App.test.js file for your tests, and a src/index.js as an entry point to the React world. You will get to know both files intimately in a later chapter. There is also a src/index.css and a src/App.css file to style your general application and components, which comes with the default style when you open them. You will modify them later as well. The create-react-app application is a npm project you can use to install and uninstall node packages. It comes with the following npm scripts for your command line:

Command Line

Runs the application in http://localhost:3000

npm start

Runs the tests

npm test

Builds the application for production

npm run build

The scripts are defined in your package.json, and your basic React application is bootstrapped.

#C1
Development team

Fetching data using React.js

Fetching Data

We’re prepared to fetch data from the Hacker News API. There was one lifecycle method mentioned that can be used to fetch data: `componentDidMount()`. Before we use it, let’s set up the URL constants and default parameters to break the URL endpoint for the API request into smaller pieces.

src/App.js

import React, { Component } from 'react';
import './App.css';
const DEFAULT_QUERY = 'redux';
const PATH_BASE = 'https://hn.algolia.com/api/v1';
const PATH_SEARCH = '/search';
const PARAM_SEARCH = 'query=';

...

In JavaScript ES6, you can use template literals for string concatenation or interpolation. You will use it to concatenate your URL for the API endpoint.

Code Playground

// ES6
const url = `${PATH_BASE}${PATH_SEARCH}?${PARAM_SEARCH}${DEFAULT_QUERY}`;
// ES5
var url = PATH_BASE + PATH_SEARCH + '?' + PARAM_SEARCH + DEFAULT_QUERY;
console.log(url);
// output: https://hn.algolia.com/api/v1/search?query=redux

This will keep your URL composition flexible in the future. Below, the entire data fetch process will be presented, and each step will be explained afterward.

src/App.js

...
class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      result: null,
      searchTerm: DEFAULT_QUERY,
    };
    this.setSearchTopStories = this.setSearchTopStories.bind(this);
    this.onSearchChange = this.onSearchChange.bind(this);
    this.onDismiss = this.onDismiss.bind(this);
  }
  setSearchTopStories(result) {
    this.setState({ result });
  }

  componentDidMount() {
    const { searchTerm } = this.state;
    fetch(`${PATH_BASE}${PATH_SEARCH}?${PARAM_SEARCH}${searchTerm}`)
      .then(response => response.json())
      .then(result => this.setSearchTopStories(result))
      .catch(error => error);
  }
  ...
}

First, we will return a real list from the Hacker News API, so the sample data is no longer used. The initial state of your component has an empty result and default search term now. The same default search term is used in the input field of the Search component, and in your first request.

Second, you use the componentDidMount() lifecycle method to fetch the data after the component mounted. The first fetch uses default search term from the local state. It will fetch “redux” related stories, because that is the default parameter

Third, the native fetch API is used. The JavaScript ES6 template strings allow it to compose the URL with the searchTerm. The URL is the argument for the native fetch API function. The response is transformed to a JSON data structure, a mandatory step in a native fetch with JSON data structures, after which it can be set as result in the local component state. If an error occurs during the request, the function will run into the catch block instead of the then block. Last, remember to bind your new component method in the constructor. You can output the local state with console.log(this.state); in your render() method to visualize it. In the next step, we use the result to render it. But we will prevent it from rendering anything, so we will return null, when there is no result in the first place. Once the request to the API has succeeded, the result is saved to the state and the App component will re-render with the updated state.

src/App.js

class App extends Component {

    ...
  render() {
    const { searchTerm, result } = this.state;
  
    if (!result) { return null; }
    
    return (
      <div className="page">
        ...
        <Table
          list={result.hits}
          pattern={searchTerm}
          onDismiss={this.onDismiss}
        />
      </div>
    );
  }
}

Now, let’s recap what happens during the component lifecycle. Your component is initialized by the constructor, after which it renders for the first time. We prevented it from displaying anything, because the result in the local state is null. It is allowed to return null for a component to display nothing. Then the componentDidMount() lifecycle method fetches the data from the Hacker News API asynchronously. Once the data arrives, it changes your local component state in setSearchTopStories(). The update lifecycle activates because the local state was updated. The component runs the render() method again, but this time with populated result in your local component state. The component and the Table component will be rendered with its content.

We used the native fetch API supported by most browsers to perform an asynchronous request to an API. The create-react-app configuration makes sure it is supported by all browsers. There are also third-party node packages that you can use to substitute the native fetch API: axios.

In the example, if (!result) was used in favor of if (result === null). The same applies for other cases as well. For instance, if (!list.length) is used in favor of if (list.length === 0) or if (someString) is used in favor of if (someString !== '').

Completely Example

src/App.js

import React, { Component } from 'react';
import './App.css';
import Search from './Search.js';
import Table from './Table.js';
const DEFAULT_QUERY = 'redux';
const PATH_BASE = 'https://hn.algolia.com/api/v1';
const PATH_SEARCH = '/search';
const PARAM_SEARCH = 'query=';

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      result: null,
      searchTerm: DEFAULT_QUERY,
    };
    this.setSearchTopStories = this.setSearchTopStories.bind(this);
    this.onSearchChange = this.onSearchChange.bind(this);
    this.onDismiss = this.onDismiss.bind(this);
  }
  setSearchTopStories(result) {
    this.setState({ result });
  }

  onSearchChange(event) {
    this.setState({ searchTerm: event.target.value });
    this.fetchData(); 

    
  }

  onDismiss(id) {
    const isNotId = item => item.objectID !== id;
    const updatedHits = this.state.result.hits.filter(isNotId);
    this.setState({
    result: Object.assign({}, this.state.result, { hits: updatedHits })
    });
  }

  fetchData(){
    const { searchTerm } = this.state;
    fetch(`${PATH_BASE}${PATH_SEARCH}?${PARAM_SEARCH}${searchTerm}`)
      .then(response => response.json())
      .then(result => this.setSearchTopStories(result))
      .catch(error => error);
  }

  componentDidMount() {
    // const { searchTerm } = this.state;
    // fetch(`${PATH_BASE}${PATH_SEARCH}?${PARAM_SEARCH}${searchTerm}`)
    //   .then(response => response.json())
    //   .then(result => this.setSearchTopStories(result))
    //   .catch(error => error);
    this.fetchData(); 
  }
  render() {
    const { searchTerm, result } = this.state;
  
    if (!result) { return null; }
    
    return (
      <div className="page">
        <Search
          value={searchTerm}
          onChange={this.onSearchChange}
        />

        <Table
          list={result.hits}
          pattern={searchTerm}
          onDismiss={this.onDismiss}
        />
      </div>
    );
  }
}

export default App;

src/Search.js

import React, { Component } from 'react';

class Search extends Component {
  render() {
    const { value, onChange } = this.props;
    return (
      <form>
        <input
          type="text"
          value={value}
          onChange={onChange}
        />
      </form>
    );
  }
}

export default Search; 

src/Button.js

import React, { Component } from 'react';

class Button extends Component {
  render() {
    const {
      onClick,
      className,
      children,
    } = this.props;

    return (
      <button
        onClick={onClick}
        className={className}
        type="button"
      >
      {children}
      </button>
    );
  }
}

export default Button;

src/Table.js

import React, { Component } from 'react';
import Button from './Button.js';

class Table extends Component {
  render() {
    const { list, pattern, onDismiss } = this.props;
    return (
      <div>
        {list.map(item =>
          <div key={item.objectID}>
            <span>
              <a href={item.url}>{item.title}</a>
            </span>
            <span>{item.author}</span>
            <span>{item.num_comments}</span>
            <span>{item.points}</span>
            <span>
              <Button onClick={() => onDismiss(item.objectID)}>
                Dismiss
              </Button>
            </span>
          </div>
        )}
      </div>
    );
  }
}

export default Table;

Output :

#C2
Development team

Installation

Installation

There are many approaches to getting started with a React application. The first we’ll explore is a CDN, short for content delivery network. Many companies use CDNs to host files publicly for their consumers. Some of these files are libraries like React, since the bundled React library is just a react.js JavaScript file. To get started with React by using a CDN, find the <script> tag in your web page HTML that points to a CDN url.

You will need two libraries: react and react-dom.

Code Playground

<script crossorigin
        src="https://unpkg.com/react@16/umd/react.development.js"
></script>
<script crossorigin
        src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"
></script>

You can also get React into your application by initializing it as node project. With a package.json file, you can install react and react-dom from the command line. However, the folder must be initialized as a npm project using npm init -y with a package.json file. You can install multiple node packages with npm:

Command Line

npm install react react-dom

This approach is often used to add React to an existing application managed with npm. You may also have to deal with Babel to make your application aware of JSX (the React syntax) and JavaScript ES6. Babel transpiles your code–that is, it converts it to vanilla JavaScript–so most modern browsers can interpret JavaScript ES6 and JSX. Because of this difficult setup, Facebook introduced create-react-app as a zero-configuration React solution. The next section will show you how to setup your application using this bootstrapping tool.

Zero-Configuration Setup

we can use create-react-app to bootstrap your application. It’s an opinionated yet zero-configuration starter kit for React introduced by Facebook in 2016, recommended for beginners by 96% of React users. In create-react-app the tooling and configuration evolve in the background, while the focus is on the application implementation.

To get started, install the package to your global node packages, which keeps it available on the command line to bootstrap new React applications:

Command Line

npm install -g create-react-app

You can check the version of create-react-app to verify a successful installation on your command line:

Command Line

create-react-app --version
*v5.0.1

Now you are ready to bootstrap your first React application. The example will be referred to as hackernews, but you may choose any name you like. First, navigate into the folder:

Command Line

create-react-app hackernews
cd hackernews
npm install react react-dom

Now you can open the application in your editor. The following folder structure, or a variation of it depending on the create-react-app version, should be presented to you:

Folder Structure

hackernews/
    README.md
    node_modules/
    package.json
    .gitignore
    public/
      favicon.ico
      index.html
      manifest.json 

    src/
      App.css
      App.js
      App.test.js
      index.css
      index.js
      logo.svg
      serviceWorker.js

This is a breakdown of the folders and files:

  • README.md: The .md extension indicates the file is a markdown file. Markdown is used as a lightweight markup language with plain text formatting syntax. Many source code projects come with a README.md file to give you initial instructions about the project. When pushing your project to a platform such as GitHub, the README.md file usually displays information about the content contained in the repository. Because you used create-react-app, your README.md should be the same as the official create-react-app GitHub repository⁴⁹.

  • node_modules/: This folder contains all node packages that have been installed via npm. Since you used create-react-app, there should already be a couple of node modules installed for you. You will rarely touch this folder, because node packages are generally installed and uninstalled with npm from the command line.

  • package.json: This file shows you a list of node package dependencies and other project configurations.

  • .gitignore: This file displays all files and folders that shouldn’t be added to your git repository when using git; such files and folders should only be located in your local project. The node_- modules/ folder is one example. It is enough to share the package.json file with others, so they can install dependencies on their end with npm install without your dependency folder.

  • public/: This folder holds development files, such as public/index.html. The index is displayed on localhost:3000 when developing your app. The boilerplate takes care of relating this index with all the scripts in src/.

  • build/ This folder is created when you build the project for production, as it holds all of the production files. When building your project for production, all the source code in the src/ and public/ folders are bundled and placed in the build folder.

  • manifest.json and serviceWorker.js: These files won’t be used for this project, so you can ignore them for now.

In the beginning, everything you need is located in the src/ folder. The main focus lies on the src/App.js file which is used to implement React components. It will be used to implement your application, but later you might want to split up your components into multiple files, where each file maintains one or more components on its own.

Additionally, you will find a src/App.test.js file for your tests, and a src/index.js as an entry point to the React world. You will get to know both files intimately in a later chapter. There is also a src/index.css and a src/App.css file to style your general application and components, which comes with the default style when you open them. You will modify them later as well. The create-react-app application is a npm project you can use to install and uninstall node packages. It comes with the following npm scripts for your command line:

Command Line

Runs the application in http://localhost:3000

npm start

Runs the tests

npm test

Builds the application for production

npm run build

The scripts are defined in your package.json, and your basic React application is bootstrapped.

README.md

A utility-first CSS framework for rapidly building custom user interfaces.

build
passing
downloads
8.7M

Documentation


For full documentation, visit tailwindcss.com

Community


For help, discussion about best practices, or any other conversation that would benefit from being searchable:
Discuss Tailwind CSS on GitHub
For casual chit-chat with others using the framework:
Join the Tailwind CSS Discord Server

Contributing


If you're interested in contributing to Tailwind CSS, please read our contributing docs before submitting a pull request.

© 2020 GitHub, Inc.,