LoginSignup
1
1

More than 3 years have passed since last update.

React + Contentful で「おみくじアプリ」を作ってみる

Last updated at Posted at 2021-01-23

はじめに

「Vueはちょくちょく使ってるけど、React触ったことないんだよなぁ」
「Contentful…なんだか今後使う事ありそうだし、使ってみたいなぁ」
そんなフロントエンジニアが、React + Contentful で "おみくじアプリ" を作った際の備忘録です。
5.gif

やる事

  • React導入
  • Contentful導入
  • つなぎ込み
  • 実装

React導入

公式のドキュメント通り

npx create-react-app react-omikuji

で環境が出来ます。(爆速!最高!)

cd react-omikuji

で環境に移動して

npm start

でローカル環境が起動します。
新しい React アプリを作る - React公式ドキュメント

Contentful導入

サインアップ

公式ページからサインアップします。
freeだとユーザー数やAPIコール数に制限がありますが、一旦freeにて。
実案件で使う際は課金が必須になると思います。

スペース作成

今回は omikuji というIDでスペースを作成します。

おみくじ結果の登録

情報として以下が必要になります。

  • タイトル (例. 大吉)
  • 本文 (例. 最高にハッピーな1日になるでしょう)

なので、上記をコンテントモデルに追加します。
1.png
Field ID

  • タイトル => title
  • 本文 => description

とします。

続いて、おみくじの結果が複数必要になるので登録していきます。
2.png
このような形で6つ、結果を登録します。
3.png

つなぎ込み

Contentfulの公式にReactでContentfulを使うチュートリアルがあるので、そちらを参考にReactでContentfulが使えるようつなぎ込みます。
Getting started with React and Contentful - Contentful公式ドキュメント

認証

https://graphql.contentful.com/content/v1/spaces/[YOUR_SPACE_ID]/explore?access_token=[YOUR_ACCESS_TOKEN]

上記に自身のスペースIDとアクセストークンを置き換えアクセスします。
するとGraphiQLの画面になるので、GraphQLクエリを以下の形式で記述します。

{
  omikujiCollection {
    items {
      title
      description
    }
  }
}

エラーがなければ認証完了です。

ReactでContentfulGraphQLを使用する

App.jsを以下に書き換えます。

App.js

import {useState, useEffect} from "react";
import './App.css';
const query = `
{
  omikujiCollection {
    items {
      title
      description
    }
  }
}
`

function App() {
  const [page, setPage] = useState(null);

  useEffect(() => {
    window
      .fetch(`https://graphql.contentful.com/content/v1/spaces/[YOUR_SPACE_ID]/`, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          Authorization: "Bearer [YOUR_ACCESS_TOKEN]",
        },
        body: JSON.stringify({ query }),
      })
      .then((response) => response.json())
      .then(({ data, errors }) => {
        if (errors) {
          console.error(errors);
        }

        setPage(data.omikujiCollection.items[0]);
      });
  }, []);

  if (!page) {
    return "Loading...";
  }

  return (
    <div className="App">
      <header className="App-header">
        <p>{page.title}</p>
        <p>{page.description}</p>
      </header>
    </div>
  );
}

export default App;

これで npm start をすれば表示されたはずです。
4.png
記述の通り0番目の内容が表示されていると思います。
ここまでエラーがなければつなぎ込みは完了です。

実装

仕様の確認

まずどのような仕様のおみくじにするのか確認です。

  • トップページ( react-omikuji/ )で「今日の運勢を占う」ボタンを押下すると、 react-omikuji/result ページに遷移し、結果が表示される
  • ランダムで結果が表示される

上記が問題なければなんでも良しとします。

ルーティング設定

ページ遷移の挙動を実現するためにreact-router-domをインストールします。

npm i react-router-dom

コンポーネント追加

トップページで使う Button と、結果ページの Result のコンポーネントを用意します。

components/Button.js
import React from "react";
import { Link } from 'react-router-dom'

export default class Button extends React.Component {
  render() {
    return (
      <Link to="/result">{this.props.text}</Link>
    )
  }
}
components/Result.js
import React from "react";

export default class Result extends React.Component {
  render() {
    return (
      <div>
        <p>{this.props.title}</p>
        <p>{this.props.description}</p>
        <a href="/react-omikuji/">トップに戻る</a>
      </div>
    )
  }
}

実装

App.jsを以下に書き換えます。

App.js
import {useState, useEffect} from "react";
import { BrowserRouter as Router, Route } from 'react-router-dom';
import Button from './components/Button';
import Result from './components/Result';
import './App.css';
const query = `
{
  omikujiCollection {
    items {
      title
      description
    }
  }
}
`

function App() {
  const [page, setPage] = useState(null);

  useEffect(() => {
    window
      .fetch(`https://graphql.contentful.com/content/v1/spaces/[YOUR_SPACE_ID]/`, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          Authorization: "Bearer [YOUR_ACCESS_TOKEN]",
        },
        body: JSON.stringify({ query }),
      })
      .then((response) => response.json())
      .then(({ data, errors }) => {
        if (errors) {
          console.error(errors);
        }
        const number = Math.floor( Math.random() * ((data.omikujiCollection.items.length - 1) + 1 - 0) ) + 0
        setPage(data.omikujiCollection.items[number]);
      });
  }, []);

  if (!page) {
    return "Loading...";
  }

  return (
    <div className="App">
      <Router basename='/react-omikuji/'>
        <Route exact path='/' render={() => <Button text='今日の運勢を占う'/>} />
        <Route exact path='/result' render={() => <Result title={page.title} description={page.description}/>} />
      </Router>
    </div>
  );
}

export default App;

ルートディレクトリ変更

トップページを react-omikuji/ とするためにpackage.jsonに以下を追記します。

package.json
"homepage": "/react-omikuji/"

完成

完成です!
5.gif
(スタイルは適宜ご調整ください。)

npm start でローカル確認が問題なければ、 npm run build でビルドされます。

あとがき

「いやいや、おみくじ判定のタイミング!」
「aタグで戻るんかい!」
などなどありますが、あくまで仕様が

  • トップページ( react-omikuji/ )で「今日の運勢を占う」ボタンを押下すると、 react-omikuji/result ページに遷移し、結果が表示される
  • ランダムで結果が表示される

上記が問題なければなんでも良しとします。

という事で…

トークン丸見え問題・APIコール数問題などなどがあるので、ヘッドレスCMS使うならSSG一択なんでしょうかね…

リンク

新しい React アプリを作る - React公式ドキュメント
Getting started with React and Contentful - Contentful公式ドキュメント

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