Build a Simple Blog with React, Next.js, and Cosmic.js GraphQL

This tutorial walks through creating a lightweight blog using React, Next.js, and Cosmic.js GraphQL, covering environment setup, dependency installation, package configuration, core component implementation, and sample GraphQL queries to fetch and display posts.

21CTO
21CTO
21CTO
Build a Simple Blog with React, Next.js, and Cosmic.js GraphQL

This article demonstrates how to build a basic blog system using React, Next.js, and Cosmic.js GraphQL.

Prerequisites

Ensure Node.js and npm are installed on your machine.

Setup

Create a project folder:

mkdir simple-react-blog
cd simple-react-blog

Add a package.json file with the required scripts and dependencies:

{
  "scripts": {
    "dev": "node server.js",
    "build": "next build",
    "start": "next build; NODE_ENV=production node server.js"
  },
  "dependencies": {
    "axios": "^0.16.2",
    "express": "^4.16.2",
    "lodash": "^4.17.4",
    "next": "^4.0.3",
    "next-routes": "^1.1.0",
    "react": "^16.0.0",
    "react-dom": "^16.0.0"
  }
}

Install the dependencies with npm i.

Core Component (index.js)

import axios from 'axios'
import _ from 'lodash'
import Footer from './partials/footer'
import Header from './partials/header'
import helpers from '../helpers'
import config from '../config'
export default class extends React.Component {
  static async getInitialProps({ req }) {
    const query = `{
      objects(bucket_slug: "${config.bucket.slug}") {
        _id
        type_slug
        slug
        title
        metadata
        created_at
      }
    }`
    return await axios.post(`https://graphql.cosmicjs.com/v1`, { query })
      .then(function (response) {
        return {
          cosmic: {
            posts: _.filter(response.data.data.objects, { type_slug: 'posts' }),
            global: _.keyBy(_.filter(response.data.data.objects, { type_slug: 'globals' }), 'slug')
          }
        }
      })
      .catch(function (error) {
        console.log(error)
      })
  }
  render() {
    if (!this.props.cosmic) return <div>Loading...</div>
    return (
      <div>
        <Header cosmic={this.props.cosmic} />
        <main className="container">
          {this.props.cosmic.posts && this.props.cosmic.posts.map(post => {
            const friendly_date = helpers.friendlyDate(new Date(post.created_at))
            post.friendly_date = friendly_date.month + ' ' + friendly_date.date
            return (
              <div className="card" data-href={`/${post.slug}`} key={post._id}>
                {post.metadata.hero.imgix_url && (
                  <a href={`/${post.slug}`} className="blog-post-hero blog-post-hero--short" style={{ backgroundImage: `url(${post.metadata.hero.imgix_url})` }}></a>
                )}
                <div className="card-padding">
                  <h2 className="blog__title blog__title--small"><a href={`/${post.slug}`}>{post.title}</a></h2>
                  <div className="blog__author">
                    <a href={`/author/${post.metadata.author.slug}`}>
                      <div className="blog__author-image" style={{ backgroundImage: `url(${post.metadata.author.metafields[0].imgix_url}?w=100)` }}></div>
                    </a>
                    <div className="blog__author-title">by <a href={`/author/${post.metadata.author.slug}`}>{post.metadata.author.title}</a> on {post.friendly_date}</div>
                  </div>
                  <div className="clearfix"></div>
                  <div className="blog__teaser droid" dangerouslySetInnerHTML={{ __html: post.metadata.teaser }}></div>
                  <div className="blog__read-more"><a href={`/${post.slug}`}>Read more...</a></div>
                </div>
              </div>
            )
          })}
        </main>
        <Footer />
      </div>
    )
  }
}

Dependencies Overview

Axios – HTTP client for GraphQL communication.

Next.js – Universal React framework.

Next‑routes – Dynamic routing.

Express – Server‑side framework.

React – UI library.

Simple GraphQL Query Example

const gql_query = `{
  objects(bucket_slug: "${config.bucket.slug}") {
    type_slug
    slug
    title
    content
    metadata
    created_at
  }
}`
return await axios.post(`https://graphql.cosmicjs.com/v1`, { query: gql_query })
  .then(function (response) {
    return {
      cosmic: {
        posts: _.filter(response.data.data.objects, { type_slug: 'posts' }),
        global: _.keyBy(_.filter(response.data.data.objects, { type_slug: 'globals' }), 'slug'),
        post: _.find(response.data.data.objects, { slug: query.slug })
      }
    }
  })
  .catch(function (error) {
    console.log(error)
  })

Conclusion

The complete source code is available on the Cosmic.js blog and GitHub, allowing you to download and customize the full blog, including dashboard components.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

ReacttutorialNext.jsGraphQLBlogCosmic.js
21CTO
Written by

21CTO

21CTO (21CTO.com) offers developers community, training, and services, making it your go‑to learning and service platform.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.