Introduction to Next.js - fetching data from API
Tags: nextjs, node, react, tutorial
Published: 2018-08-24 23:42:50

---
title: Introduction to Next.js - fetching data from API
published: true
description: Second part to the basics of next.js
tags: [nextjs, node, react, tutorial]
---

Following from the last tutorial


{% link https://dev.to/aurelkurtula/introduction-to-the-basics-of-nextjs-1loa %}

Today we'll cover

1. Fetching data from an API.
2. Performing CRUD operations onfetch API.

In future tutorials I might cover how we could actually incorporate express within next.js and create our own API, but for now I am going to use an NPM package called [json-server](https://github.com/typicode/json-server). It's a fantastic tool to quickly run a local REST API. As it states in the documentation "a full fake REST API with zero coding in less than 30 seconds". As this is not a tutorial for `json-server` I am not going to say much just that I've added a JSON file with all our data at `./data/db.json` and then ran `json-server data/db.json --port 4000`, giving us a REST API at port 4000 (read the documentation if you want to learn more on [json-server](https://github.com/typicode/json-server)). Leave that running in a separate terminal window and let's get on. 

I am going to assume that you've read the [last tutorial](https://dev.to/aurelkurtula/introduction-to-the-basics-of-nextjs-1loa) and if you are following along you have already cloned the files we have so far ([github -  part one](https://github.com/aurelkurtula/basics-of-nextJS/tree/part1)). 

## Fetching data from API

In the last tutorial we used stateless functional components. This time we'll need to convert some of those components to class based, starting with `./pages/index.js`.

```javascript
const Index = (props) => ( <Layout> ... </Layout>)
Index.getInitialProps = async ({ }) => { ...}
export default Index
```

That's what we have from the [previous tutorial](https://dev.to/aurelkurtula/introduction-to-the-basics-of-nextjs-1loa). Let's convert that into a class component and fetch data from the API

```javascript
import React, { Component } from 'react'
import fetch from 'isomorphic-unfetch'
import Layout from '../components/Layout';
import Photo from '../components/Photo';

export default class extends Component {
  static async getInitialProps() {
    const res = await fetch('http://localhost:4000/photos')
    const images = await res.json()
    return { images }
  }
  componentWillMount() {
    this.setState({
      images: this.props.images
    })
  }
  render() {
    return (
      <Layout>
         {
          this.state.images.map((image, key) => <Photo id={key} id={key} data={image} />)
         }
      </Layout>
    )
  }
}
```

As you can see, the core code is the same. We just wrapped what we had into a react class component. 

When using next.js we do not have access to the browser's fetch API, hence we need to install the `isomorphic-unfetch` library (`npm i -S isomorphic-unfetch`) which implements the same functionality as the browser's fetch.

Just as previously, `getInitialProps` pushes the fetched data into the props. We then inject that data into the component state, via `componentWillMount`. Basic react stuff - we need access to the data via the state rather than props so that we'll be able to propagate data changes through the app.

## Functionality to like a photo

Thinking back to the [previous tutorial](https://dev.to/aurelkurtula/introduction-to-the-basics-of-nextjs-1loa), we have a likes button that shows the number of likes. We of course want the ability to increase the likes upon button click

![](https://thepracticaldev.s3.amazonaws.com/i/wcniyujp3p1l0l8ulgv2.png)

As usual in react development we are going to create the functionality in the Index page component (`./pages/index.js`) and pass it down as a prop (this is why [learning redux](https://dev.to/aurelkurtula/a-beginners-introduction-to-working-with-redux-in-react-13k) is great in these cases)

```javascript
...
LikesEntry(id){
    let images = this.state.images
    let image = images.find( i => i.id === id )
    image.likes = parseInt(image.likes) + 1
    this.setState({
        images
    })
    fetch(`http://localhost:4000/photos/${id}`, {
        method: 'PUT',
        headers: {
          'Accept': 'application/json',
          'Content-Type': 'application/json'
        },
        body: JSON.stringify(image)
      })

}
render(){
    return (
        <Layout>
            {
                this.state.images.map((image, key) => 
                    <Photo 
                        LikesEntry={this.LikesEntry.bind(this)} 
                        id={image.id} 
                        key={key} data={image} /> )
            }
        </Layout>
    )
}
...
```


When the likes button is clicked, `LikesEntry` get's triggered. In there we increase the number of likes to the image that's being pressed. That change is pushed back to the state, then we perform a put request where the server also gets the changes. 

The button that's being pressed is actually two components deep. Above we pass `LikesEntry` to the `./components/Photo.js` component (via props). The `Photo` component would equally pass `LikesEntry` to the `CommentsFunctionality` component

In `./components/Photo.js`

```javascript
<CommentsFunctionality 
    LikesEntry={() => 
        props.LikesEntry(props.data.id)}
        commentsNum={props.data.comments.length}
        likes={props.data.likes} />
```

And lastly the `./components/InteractiveButtons.js` get's to use it upon click:

```javascript
export default ({likes, LikesEntry, commentsNum}) => (
    <div className="meta">
        <button className="heart" onClick={LikesEntry} ><MdFavoriteBorder />{likes}</button>
        <p><MdModeComment />{ commentsNum }</p>
```

That's it with the likes button. On click the component state updates along with the server.

(As you can see I added the comments number there as well, just to make UI feel complete)

## Getting individual photograph

Almost the same process is involved in the `./pages/photo.js` component, converting it to a class component and add props to state

The same process as before, now a single image needs to be fetched. So `./pages/photo.js` component needs to be converted into a class component.

```javascript
import react, { Component } from 'react'
import fetch from 'isomorphic-unfetch'
import Layout from '../components/Layout';
import Photo from '../components/Photo';
import CommentsFunctionality from '../components/InteractiveButtons'

export default class extends Component {
    static async getInitialProps({query}) {
        const {id} = {...query}
        const res = await fetch(`http://localhost:4000/photos/${id}`)
        const image = await res.json() 
        return { image } 
    }
    componentWillMount(){
        this.setState({
            image: this.props.image
        })
    }
    render(){
        return(
            <Layout>
                ...
                    <img src={`/static/art/${this.state.image.image}.jpg`} alt=''/>
                    <CommentsFunctionality />
                </div>
                <div className="comments">
                    <p className="tagline">{this.state.image.tagline}</p>
                    {
                        this.state.image.comments.map((comment, key) => <p key={key}><strong>{comment.user}:</strong>{comment.body}</p>)
                    }
                    <form className="comment-form">
                        <input type="text" ref="author" placeholder="Author" />
                        <input type="text" ref="comment"  placeholder="comment..." />
                        <input type="submit" />
                    </form>
                ...

```

Exactly as we did in the `Index` component, the data is fetched and injected in the component state. The returned JSX (react's version of HTML) is exactly the same just that we return from `this.state`. Also `ref` is added to the form inputs. ("Refs provide a way to access DOM nodes or React elements created in the render method" ([react docs](https://reactjs.org/docs/refs-and-the-dom.html)))


## Add comments to the image

Finally we need to deal with the form. 

![](https://res.cloudinary.com/practicaldev/image/fetch/s--9bHf5DQ5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/irlbts6oerwyguyksoo3.png)

Lets add the functionality which adds a comment to the state and the server. Start by creating the `onSubmit` functionality and linking it to the form.

```javascript
submitComments(e){
    e.preventDefault();
    const user = this.refs.author.value;
    const body = this.refs.comment.value;
    const comments = this.state.image.comments;
    comments.push({user, body})
    this.setState({comments})
    fetch(`http://localhost:4000/photos/${this.state.image.id}`, {
        method: 'PUT',
        headers: {
          'Accept': 'application/json',
          'Content-Type': 'application/json'
        },
        body: JSON.stringify(this.state.image)
      })
}
...
<form className="comment-form" onSubmit={(e)=> this.submitComments(e)} >
    <input type="text" ref="author" placeholder="Author" />
    <input type="text" ref="comment"  placeholder="comment..." />
    <input type="submit" />
</form>
```

That's about it!

The code can be found at the same repository but in [part2 branch](https://github.com/aurelkurtula/basics-of-nextJS/tree/part2).

Next time we'll explore how to add express to this next.js project and recreate the basic API required for this project