LoginSignup
12
2

Next.jsとGoogleスプレッドシートを連携させて動的ページを作ってみた

Posted at

Googleスプレッドシートをデータベースとして扱い、スプレッドシートの値をWebサイト上に表示したくなるときありますよね(?)

今回は次のようなアプリを作ってみました!

  • 会社情報をスプレッドシートで管理する
  • 会社情報が追加(行の追加)されるとページを生成する
  • Next.jsのDynamic Routesで動的にページを生成する

http://XXXXXX/company/a-companyにアクセスすると各社の情報が見れるようになります。
CleanShot 2023-12-03 at 09.55.48@2x.jpg

Googleスプレッドシートの用意

下記のようなシートを作成します。
CleanShot 2023-12-02 at 10.10.16@2x.jpg

次にGASに下記のコードを追加します。

function readData() {
  const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  const sheet1 = spreadsheet.getSheetByName('シート1');
  const lastRow = sheet1.getLastRow();
  const data_range = sheet1.getRange(`A2:D${lastRow}`);
  const data_values = data_range.getValues();

  const return_data = data_values.map(data_row => {
    return {
      id: data_row[0], // スプレッドシートのA列の値を追加
      companyName: data_row[1], // スプレッドシートのB列の値を追加
      companyLogo: data_row[2], // スプレッドシートのC列の値を追加
      sales: data_row[3], // スプレッドシートのD列の値を追加
    }
  });
  console.log(return_data) 
  return return_data;
}
 
function doGet() {
    const data = readData();
    const response = ContentService.createTextOutput();
    response.setMimeType(ContentService.MimeType.JSON);
    response.setContent(JSON.stringify(data));
    return response;  
}

こちらのコードは下記の記事を参考にしております。

readData関数でスプレッドシート内のデータを取得してjson形式でデータを返しています。
return_dataの中身がこちらになります。

[ { id: 'a-company',
    companyName: 'A農業',
    companyLogo: '',
    sales: 300 
  },
  { id: 'b-company',
    companyName: 'B工業',
    companyLogo: '',
    sales: 400 
  },
  { id: 'c-company',
    companyName: 'C Tech Inc',
    companyLogo: '',
    sales: 1000 
   } 
]

doGet関数内のContentServiceでGASで表示されるURLでテキストを確認できるようになります。
右上の「デプロイ」のボタンを押します。
CleanShot 2023-12-03 at 06.24.50@2x.jpg
新しいデプロイをすると、URLが発行されてそのURLにアクセスすると先程確認したJSON形式のデータがブラウザで確認できるようになります。

あとは、Next.jsでそのURLからデータをフェッチして画面に表示させることができれば完成です。

Next.jsで動的にページを生成する

プロジェクトの作成

Next.jsのプロジェクトを作成します。
プロジェクトの作り方は公式ドキュメントを参考にしてもらえば問題ないかなと思うのでここでは、省略します。
公式ドキュメント - Next.js Getting Started Installation

動的ページの作成

まずは、動的ページのテンプレートを作成します。下記のようにページを作成します。
公式ドキュメント - Next.js / Dynamic Routes

src
└ app
  └ company
    └ [slug]
    └ page.tsx
    

page.tsxには一旦下記のように記述しておきましょう。

export default function Page({ params }: { params: { slug: string } }) {
  return <div>Company Name: {params.slug}</div>
}

この構成でページを作成することで下記のようなURLにアクセスしたときにページを表示させることができます。

http:XXXX.com/company/a-works
http:XXXX.com/company/b-works

ブラウザでの表示
CleanShot 2023-12-02 at 08.33.30@2x.jpg

次にGoogleスプレッドシートからデータを取得してくる処理を記述します。

// src/app/company/[slug]/page.tsx

'use client'
import React, { useState, useEffect } from 'react';

export default function Page({ params }: { params: { slug: string } }) {
  useEffect(() => {
    fetch('発行されたURL')
      .then(response => response.json())
      .then(data => {
        console.log(data);
      })
      .catch(err => {
        console.log(err);
      });
  }, []);

  return (
    <section>
      <div>Company Name: {params.slug}</div>
    </section>
  )
}

console.log(data);で確認するとデータが入ってきているのがわかります。
CleanShot 2023-12-03 at 09.01.14@2x.jpg

useStateで会社情報をさせます。
また、今回は会社情報の詳細ページを表示させたいのでfindで検索しています。

'use client'
import React, { useState, useEffect } from 'react';

export default function Page({ params }: { params: { slug: string } }) {
  const [company, setCompany] = useState(null);
  
  useEffect(() => {
    fetch('発行されたURL')
      .then(response => response.json())
      .then(data => {
        const selectedCompany = data.find(c => c.id === params.slug);
        setCompany(selectedCompany);
      })
      .catch(err => {
        console.log(err);
      });
  }, [params.slug]); 

  if (!company) {
    return <div>Loading...</div>;
  }

  return (
    <section>
      <div>Company Name: {params.slug}</div>
    </section>
  )
}

あとはreturn文の中にcompanyに保持されている情報を出力させます。

tailiwindで適当にスタイリングしています。

'use client'
import React, { useState, useEffect } from 'react';

export default function Page({ params }: { params: { slug: string } }) {
  const [company, setCompany] = useState(null);
  
  useEffect(() => {
    fetch('https://script.google.com/macros/s/AKfycbz7ZSP4g9roCTeTOYpL7RjWHO2E2oFo48bVT-4SdHk8ak8IIoyXbu9DK6FBN2iVTyqi/exec')
      .then(response => response.json())
      .then(data => {
        const selectedCompany = data.find(c => c.id === params.slug);
        setCompany(selectedCompany);
      })
      .catch(err => {
        console.log(err);
      });
  }, [params.slug]); 

  if (!company) {
    return <div>Loading...</div>;
  }

  return (
    <section className="">
      <div className="max-w-md rounded overflow-hidden shadow-lg p-4 bg-white shadow-lg">
        <h1 className="font-bold text-2xl mb-2 text-gray-700">会社名:{company.companyName}</h1>
        <div className="flex justify-center">
          <img className="w-96" src={company.companyLogo} alt={`${company.companyName} logo`} />
        </div>
        <p className="font-bold text-2xl mb-2 text-gray-700 mt-4">売上: {company.sales}</p>
      </div>
    </section>
  )
}

こんな形で各ページを作成することができました。(左から下記のURLにアクセスしたときの表示)

  • http://XXXXXX/company/a-company
  • http://XXXXXX/company/b-company
  • http://XXXXXX/company/c-company
    CleanShot 2023-12-03 at 16.54.11@2x.jpg

まとめ

意外と簡単にできたし、アイディア次第ではわざわざ大掛かりな開発をしなくても、少工数でやりたいことを実現できることがありそうだなと感じました。

ちなみに、今回使った会社のロゴはChatGPTに生成してもらいました。

12
2
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
12
2