LoginSignup
1
1

More than 1 year has passed since last update.

NEXT.JS + Sanity.io 画像一覧アプリを作ってみた! (最新2022年8月版)

Last updated at Posted at 2022-08-03

Desktop - 1next.png

今回は、NEXT.JSとSanity.ioを使って簡単な画像一覧アプリを作成します。完成は下記の通りです:blush:

キャラクター画像は、こちらのサイトから使っています。

初期画面

それぞれのカードをクリックすると、キャラクターの説明リンクに飛びます!

image.png

zoroをクリックすると、”localhost:3000/character/zoro"に遷移します。Homeボタンを押すと”localhost:3000/”に戻ります。

image.png

sanity.ioに新しい画像データを保存すると、ブラウザに表示されます。

image.png
:arrow_down:
image.png

下記の動画を参考に作成しました。まずこちらの動画を参考にされてください。:arrow_down:

参考動画:iphone:

NEXT.JSのSet up

npx create-next-app@latest frontend

Sanity.ioのSet up

sanity init

>Create new project: "yes"

>Your project name: "backend"

>Use the default dtaset configuration? "yes"

>Project output path: "Enter"

>Select project template: "Clean project with no predefined schemas"

モジュールをインストール

nextjsアプリケーションに下記のモジュールをインストールします。

npm install next-sanity @sanity/image-url

ここまでで必要な準備は整ったので、次はコードを書いていきます。

image.png

image.png

image.png

index.js

index.js
import { sanityClient, urlFor } from '../sanity'
import Link from 'next/link'

const Home = ({ characters }) => {

  return (
    <div>
      {characters && (
        <div>
          <h1>Characters</h1>
          <div
            style={{ display: 'grid', gap: '1px', gridTemplateColumns: '2fr 2fr 2fr' }}
          >

            {characters.map((character) => (
              <Link
                className='card'
                key={character._id}
                href={`character/${character.slug.current}`}>
                <div className='card'>
                  <img
                    src={urlFor(character.image)}
                    alt={character.name}
                    style={{ height: '70%', }}
                  />
                  <h3>{character.name}</h3>
                </div>
              </Link>
            ))}
          </div>
        </div>
      )}
    </div>
  )
}


export const getServerSideProps = async () => {
  const query = '*[_type == "character"]'
  const characters = await sanityClient.fetch(query);

  if (!characters.length) {
    return {
      props: {
        characters: []
      },
    }
  } else {
    return {
      props: {
        characters: characters,
      }
    }
  }
}

export default Home;

[slug].js

[slug].js
import Link from "next/link";
import { sanityClient, urlFor } from "../../sanity";

const Character = ({ name, image }) => {
  return (
    <div>
      <h1><b>{name}</b></h1>
      <img
        style={{ height: '300px' }}
        src={urlFor(image)} alt={name}
      />
      <br />
      <Link href="/">
        <button>Home</button>
      </Link>
    </div>
  )
}

export const getServerSideProps = async (pageContext) => {
  const pageSlug = pageContext.query.slug;
  const query = `*[ _type == "character" && slug.current == $pageSlug][0]{
    name,
    image,
  }`

  const character = await sanityClient.fetch(query, {
    pageSlug
  })
  if (!character) {
    return {
      props: null,
      notFound: true,
    }
  } else {
    return {
      props: {
        name: character.name,
        image: character.image,
      }
    }
  }
}

export default Character

sanity.js

このファイルが設定ファイルになります。

sanity.js
import { createClient } from 'next-sanity'
import createImageUrlBuilder from '@sanity/image-url'

const config = {
  dataset: process.env.NEXT_PUBLIC_SANITY_DATASET || 'production',
  projectId: process.env.NEXT_PUBLIC_SANITY_PROJECT_ID,
  apiVersion: '2021-10-21',
  useCdn: process.env.NODE_ENV === 'production',
}

export const sanityClient = createClient(config)

export const urlFor = (source) => createImageUrlBuilder(config).image(source)

globals.css

cardのスタイルだけ追加しました。

globals.css
html,
body {
  padding: 0;
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
    Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
}

a {
  color: inherit;
  text-decoration: none;
}

* {
  box-sizing: border-box;
}

@media (prefers-color-scheme: dark) {
  html {
    color-scheme: dark;
  }
  body {
    color: white;
    background: black;
  }
}

.card{
  /* preview */
width: 200px;
height: 260px;
background-color: #fff;
margin: 5px auto;
padding: 5px;

/* border */
border: 2px solid #ccc;

/* border-radius */
border-radius: 15px;

/* box-shadow */
box-shadow: 0px 8px 16px -2px rgba(10,10,10,0.1), 0px 0px 0px 1px rgba(10,10,10,0.02);
}

.env

NEXT_PUBLIC_SANITY_DATASET="datasetを記述"
NEXT_PUBLIC_SANITY_PROJECT_ID="projectIdを記述"

schemas/character.js

character.js
export default {
  name: 'character',
  title: 'Character',
  type: 'document',
  fields: [
    {
      name: 'name',
      title: 'Name',
      type: 'string',
    },
    {
      name: 'image',
      title: 'Image',
      type: 'image',
      options: {
        hotspot: true,
      }
    },
    {
      name: 'slug',
      title: 'Slug',
      type: 'slug',
      options: {
        source: 'name',
        maxLength: 100,
      }
    },
  ]
}

参考動画

さいごに

今度は、Airbnbクローンを自作してみたいですね!
参考動画では、Google maps Platformを使っています。こちらは、無料制限がありますのでご注意ください。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1