DEV Community

Cover image for Next js simple blog
Andi Ismail
Andi Ismail

Posted on

Next js simple blog

Membuat blog sederhana

https://picsum.photos/
https://jsonplaceholder.typicode.com/
https://nextjs.org/docs/api-reference/next/image#remote-patterns
import styles from "../styles/Home.module.css"
import Image from "next/image"
import Link from "next/link"
import {useRouter} from "next/router"

pnpm create next-app myblog
typescript > No
eslint > No
Enter fullscreen mode Exit fullscreen mode

kita pakai css bawaan

Image description 1

Image description 2

//index.jsx

import styles from "../styles/Home.module.css"
export default function Home (){
  return (
    <main className={styles.main}>
      <h1>My Blog</h1>
    </main>
  )
}
Enter fullscreen mode Exit fullscreen mode

Image description3

Image description4

selanjutnya kita akan melakukan fetching data,

import styles from "../styles/Home.module.css"

export default function Home ({data, page}){

  return (
    <main className={styles.main}>
      <h1>My Blog {page}</h1>

    </main>
  )
}

export async function getServerSideProps(ctx){

  console.info(ctx)
  const result = await fetch("https://jsonplaceholder.typicode.com/posts?_page=" + ctx.query.page)
  const data = await result.json()

  return {
    props : {
      data: data,
      page : ctx.query.page || 1
    }
  }
} 
Enter fullscreen mode Exit fullscreen mode

Image description5

Image description6

//index.jsx

import styles from "../styles/Home.module.css"

export default function Home ({data, page}){

  return (
    <main className={styles.main}>
      <h1>My Blog {page}</h1>

      <div className="styles.cardWrapper">

        {data.map((e)=>(
          <div key={e.id}>
            <h3>{e.title}</h3>
            <p>{e.body}</p>
          </div>
        ))}
      </div>

    </main>
  )
}

export async function getServerSideProps(ctx){

  console.info(ctx)
  const result = await fetch("https://jsonplaceholder.typicode.com/posts?_page=" + ctx.query.page)
  const data = await result.json()

  return {
    props : {
      data: data,
      page : ctx.query.page || 1
    }
  }
} 
Enter fullscreen mode Exit fullscreen mode

Image description8

Image description9

kita sudah berhasil menampilkan data jsonnya sekarang kita akan menampilkan gambarnya dari picsum.photos

Image description11

Image description12

//index.jsx

import styles from "../styles/Home.module.css"

export default function Home ({data, page}){

  return (
    <main className={styles.main}>
      <h1>My Blog {page}</h1>

      <div className="styles.cardWrapper">

        {data.map((e)=>(
          <div key={e.id}>

            <img src={ `https://picsum.photos/seed/${e.id}/500/300` } alt={e.title} />
            <h3>{e.id} . {e.title}</h3>
            <p>{e.body}</p>
          </div>
        ))}
      </div>

    </main>
  )
}

export async function getServerSideProps(ctx){

  console.info(ctx)
  const result = await fetch("https://jsonplaceholder.typicode.com/posts?_page=" + ctx.query.page)
  const data = await result.json()

  return {
    props : {
      data: data,
      page : ctx.query.page || 1
    }
  }
} 
Enter fullscreen mode Exit fullscreen mode

selanjutnya kita akan menampilkan gambar dengan images next js

Image description next image

next image config

//next.config.js

/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
  images  : {
    remotePatterns : [
      {
        protocol : 'https',
        hostname : 'picsum.photos'
      }
    ]
  }
}

module.exports = nextConfig

Enter fullscreen mode Exit fullscreen mode

error

import styles from "../styles/Home.module.css"
import Image from "next/image"


export default function Home ({data, page}){

  return (
    <main className={styles.main}>
      <h1>My Blog {page}</h1>

      <div className="styles.cardWrapper">

        {data.map((e)=>(
          <div key={e.id} className={styles.blogCard}>

            <Image 
            src={ `https://picsum.photos/seed/${e.id}/200/200` } 
            alt={e.title} 
            width={200}
            height={200}
            />

            <h3>{e.id} . {e.title}</h3>
            <p>{e.body}</p>
          </div>
        ))}
      </div>

    </main>
  )
}

export async function getServerSideProps(ctx){

  console.info(ctx)
  const result = await fetch("https://jsonplaceholder.typicode.com/posts?_page=" + ctx.query.page)
  const data = await result.json()

  return {
    props : {
      data: data,
      page : ctx.query.page || 1
    }
  }
} 
Enter fullscreen mode Exit fullscreen mode

akan ada pesan error karena kita mengganti config js, jadi servernya kita matikan dulu, kemudian start ulang.

tampil berhasil

selanjutnya kita akan menampilkan prev dan next dibagian bawah page kita

//index.jsx

import styles from "../styles/Home.module.css"
import Image from "next/image"
import {useRouter} from "next/router"

export default function Home ({data, page}){

  const router = useRouter()

  //function untuk pagination
  const nextPage = ()=>{
    router.push(`/?page=${page + 1}`)
  }

  return (
    <main className={styles.main}>
      <h1>My Blog {page}</h1>

      <div className="styles.cardWrapper">

        {data.map((e)=>(
          <div key={e.id} className={styles.blogCard}>

            <Image 
            src={ `https://picsum.photos/seed/${e.id}/200/200` } 
            alt={e.title} 
            width={200}
            height={200}
            />

            <h3>{e.id} . {e.title}</h3>
            <p>{e.body}</p>
          </div>
        ))}
      </div>

      <div className={styles.btnPagination}>
        <button>prev</button>
        <button onClick={nextPage}>next</button>
      </div>

    </main>
  )
}

export async function getServerSideProps(ctx){

  console.info(ctx)
  const result = await fetch("https://jsonplaceholder.typicode.com/posts?_page=" + ctx.query.page)
  const data = await result.json()

  return {
    props : {
      data: data,
      page : parseInt(ctx.query.page) || 1
    }
  }
} 
Enter fullscreen mode Exit fullscreen mode

next page

sekarang kita ke function prev page

import styles from "../styles/Home.module.css"
import Image from "next/image"
import {useRouter} from "next/router"

export default function Home ({data, page}){

  const router = useRouter()

  //function untuk pagination
  const nextPage = ()=>{
    router.push(`/?page=${page + 1}`)
  }

  const prevPage =()=>{
    if (page==1){
      return
    }
    router.push(`/?page=${page - 1}`)
  }



  return (
    <main className={styles.main}>
      <h1>My Blog {page}</h1>

      <div className="styles.cardWrapper">

        {data.map((e)=>(
          <div key={e.id} className={styles.blogCard}>

            <Image 
            src={ `https://picsum.photos/seed/${e.id}/200/200` } 
            alt={e.title} 
            width={200}
            height={200}
            />

            <h3>{e.id} . {e.title}</h3>
            <p>{e.body}</p>
          </div>
        ))}
      </div>

      <div className={styles.btnPagination}>
        <button onClick={prevPage}>prev</button>
        <button onClick={nextPage}>next</button>
      </div>

    </main>
  )
}

export async function getServerSideProps(ctx){

  console.info(ctx)
  const result = await fetch("https://jsonplaceholder.typicode.com/posts?_page=" + ctx.query.page)
  const data = await result.json()

  return {
    props : {
      data: data,
      page : parseInt(ctx.query.page) || 1
    }
  }
} 
Enter fullscreen mode Exit fullscreen mode

selanjutnya kita akan buat Link tag a yang akan mengarahkan detailnya, sebelumnya buat folder detail dan files [id].jsx

//detail > [id.jsx]

import styles from "../../styles/Home.module.css"
import Image from "next/image"
import { useRouter } from "next/router"


export default function Details ({data}){
    const router = useRouter()

    return (
        <main className={styles.main}>
            <h1>{data.title}</h1>
            <Image 
                src={`https://picsum.photos/seed/${data.id}/900/500`}
                width={900}
                height ={500}
                alt ={data.title}
             />

            <p>{data.body}</p>
            <button onClick={()=>{router.back()}}>back</button>
        </main>
    )
}

export async function getServerSideProps(ctx){
    const result =await fetch("https://jsonplaceholder.typicode.com/posts/" + ctx.params.id)
    const data = await result.json()

    return {
        props : {
            data : data
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

tambahkan Link

//index.jsx

import styles from "../styles/Home.module.css"
import Image from "next/image"
import Link from "next/link"
import {useRouter} from "next/router"

export default function Home ({data, page}){

  const router = useRouter()

  //function untuk pagination
  const nextPage = ()=>{
    router.push(`/?page=${page + 1}`)
  }

  const prevPage =()=>{
    if (page==1){
      return
    }
    router.push(`/?page=${page - 1}`)
  }



  return (
    <main className={styles.main}>
      <h1>My Blog {page}</h1>

      <div className="styles.cardWrapper">

        {data.map((e)=>(
          <div key={e.id} className={styles.blogCard}>

            <Image 
            src={ `https://picsum.photos/seed/${e.id}/200/200` } 
            alt={e.title} 
            width={200}
            height={200}
            />

            <h3>{e.id} . {e.title}</h3>
            <p>{e.body}</p>

            <Link href={`/details/${e.id}`}>Detail</Link>
          </div>
        ))}
      </div>

      <div className={styles.btnPagination}>
        <button onClick={prevPage}>prev</button>
        <button onClick={nextPage}>next</button>
      </div>

    </main>
  )
}

export async function getServerSideProps(ctx){

  console.info(ctx)
  const result = await fetch("https://jsonplaceholder.typicode.com/posts?_page=" + ctx.query.page)
  const data = await result.json()

  return {
    props : {
      data: data,
      page : parseInt(ctx.query.page) || 1
    }
  }
} 
Enter fullscreen mode Exit fullscreen mode

Myblog

halaman 2

Details

selanjutnya kita akan menambahkan css

//Home.module.css

.main {
  min-height: 100vh;
  padding: 4rem 0;
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: flex-start;
  max-width: 900px;
  margin: 0 auto;
}

.cardWrapper {
  display: flex;
  flex-direction: column;
  gap: 40px;
}

.blogCard {
  display: flex;
  gap: 20px;
  padding: 20px;
  border: 1px dashed whitesmoke;
}
Enter fullscreen mode Exit fullscreen mode

blog4

Details

https://github.com/andiks2018/JvalleyNext-simpleblog.git

Top comments (0)