59
28

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

犬無料10連ガチャを回していかないか?【React】

Last updated at Posted at 2022-12-07

この記事は「【マイスター・ギルド】本物のAdvent Calendar 2022」5日目の記事です。
他の記事も要チェックや!!

はじめに

みなさまこんにちは。sawaです。

「はよ犬ガチャを回させんかい!」という、犬ジャンキーの方は早速下のリンクからどうぞ。

犬ってかわいいですよね。
時間に余裕があってもなくても犬を見て癒されている方は多いんじゃないでしょうか。
今日はそんな犬の画像を提供してくれるAPIを紹介したいと思います。

ただ紹介するだけでは面白くないので、今回はReactで10連ガチャ風に実装してみました。
なぜReactなのかというと、勉強中だからです。
なぜ10連ガチャ風なのかというと、10連ガチャをたくさん回せて犬も見れるとなるととっても嬉しいからです。
対戦よろしくお願いします。

犬APIについて

犬好きの皆様にぜひ知っていただきたいAPIがあります。
その名は「DogAPI」。そのまんまですね。

これはスタンフォード大学が提供している犬の画像のデータセットを、有志がAPIで取得できるようにしてくれたものです。

犬種別に取得できたり、エンドポイントに数字を指定して複数取得できたりします。
ブラウザ上で試せるので、自分で試したい方はリンク先へどうぞ。

また、自分ちの犬の写真をPRで投げると追加してくれるらしいです。
犬飼いエンジニアの方は参加してみてはいかがでしょうか。

Reactで10連ガチャ風に実装する

早速作っていきましょう。

犬APIを叩く

まずは犬APIを叩きます。

DogCard.jsx
import { useEffect, useState } from "react";
import axios from "axios";

export const DogCard = () => {
  const [posts, setPosts] = useState([]);

  //APIを叩いてpostsにJSONデータを格納
  useEffect(() => {
    axios.get("https://dog.ceo/api/breeds/image/random/10").then((res) => {
      setPosts(res.data.message);
    });
  }, [setPosts]);

  return (
    <SDogCard>
      <ul>
        {posts.map((post, i) => {
          return (
            <li key={i} >
              <img src={post} width={500} alt="犬の画像" loading="lazy"  />
            </li>
          );
        })}
      </ul>
    </SDogCard>
  );
};

結果

localhost_3000_ (1).png

補足

  • https://dog.ceo/api/breeds/image/random/10と、エンドポイントに「10」と指定することで10枚の画像を取得しました。10連ガチャだからね。
  • 取得した画像の大きさがバラバラなので、一旦<img src={post} width={500} alt="犬の画像" loading="lazy" />としてwidthを指定しています。とりあえずの処置なので後で調整します。

ボタンの実装

上述した実装方法だと画面更新で画像が切り替わるのですが、それでは味気ないので画像を表示するボタンを実装していきます。
「初回の結果を表示するボタン」と、「2回目以降の結果を表示するボタン」の2種類を作ります。

初回の結果を表示するボタンの実装

Top.jsx
export const Top = () => {
  const [showDogImageFlag, setShowDogImageFlag] = useState(false);
  const onClickShowDogImage = () => {
    setShowDogImageFlag(!showDogImageFlag);
  };

  return (
    <STop>
      <h1 className="title">犬無料10連ガチャ</h1>
      <div
        className="showResultArea"
        showresult={showDogImageFlag ? "false" : "true"}
      >
        <DogCard />
      </div>
      <div className="showResultButtonArea">
        <input
          type="button"
          value="回す!"
          onClick={onClickShowDogImage}
          className="showResultButton"
          showresult={showDogImageFlag ? "false" : "true"}
        />
      </div>
    </STop>
  );
};
/*犬の画像を表示/非表示*/
  .showResultArea[showresult="false"] {
    display: inline-block;
    padding: 20px;
  }
  .showResultArea[showresult="true"] {
    display: none;
  }

/*ボタンを表示/非表示*/
  .showResultButton[showresult="true"] {
    display: inline-block;
  }
  .showResultButton[showresult="false"] {
    display: none;
  }

結果

スクリーンショット_20221205_155829.png
サイトの初回表示時にこの画面が表示されます。
この赤矢印で示しているボタンを押すと結果が表示されます。

補足

  • ボタンを押すとshowDogImageFlagの真偽値が切り替わるようになっています。それを受けてCSSで犬画像とボタンの表示非表示を制御しています。
  • タイトルやボタンのスタイルは適当にCSSを当てています。グラデーションを設定するだけで情報量が多くなるので適当にそれっぽいスタイルを当てたいときにオススメです。

2回目以降の結果を表示するボタンの実装

DogCard.jsx
export const DogCard = () => {
  const [posts, setPosts] = useState([]);
+  const [renew, setRenew] = useState("");

  //APIを叩いてpostsにJSONデータを格納
  useEffect(() => {
    axios.get("https://dog.ceo/api/breeds/image/random/10").then((res) => {
      setPosts(res.data.message);
    });
-  }, [setPosts]);
+  }, [setPosts, renew]);

  return (
    <SDogCard>
      <ul>
        {posts.map((post, i) => {
          return (
            <li key={i}>
              <img src={post} alt="犬の画像" loading="lazy" />
            </li>
          );
        })}
      </ul>
+      <input
+       type="button"
+       value="もう一回!"
+       onClick={() => setRenew((renew) => renew + 1)}
+      />
    </SDogCard>
  );
};

結果

スクリーンショット_20221205_155938.png

赤矢印で指し示しているボタンを押すと、新しい結果画面が読み込まれます。

補足

  • 「もう一回!」ボタンを押す度にAPIが叩かれるように、新たにstateを追加しました。
    こちらは下記サイト様を参考にさせていただきました。ありがとうございます!

CSSで結果画面をガチャっぽくする

ガチャの結果画面で気になるものといえば、そう、レアリティですね。

figmaで適当に画像をつくります。
SSR.png

それを画像の左上に重ねて、画像の大きさを均一にしたりします。
スクリーンショット_20221205_165047.png

おお!一気にガチャっぽくなりましたね。

ちなみにこの世の犬はみな等しく可愛いので全員SSRです。

ローディングを入れる

export const DogCard = () => {
  const [posts, setPosts] = useState([]);
  const [renew, setRenew] = useState("");
+  const [isLoading, setIsLoading] = useState(true);

  //APIを叩いてpostsにJSONデータを格納
  useEffect(() => {
+    setIsLoading(true);
    axios
      .get("https://dog.ceo/api/breeds/image/random/10")
      .then((res) => {
        setPosts(res.data.message);
+        setIsLoading(false);
      })
      .catch((error) => {
        console.log(error);
+        setIsLoading(true);
      });
  }, [setPosts, renew]);

  return (
    <SDogCard>
      <div>
+        {isLoading ? (
+          <div className="spinner-box">
+            <div className="three-quarter-spinner"></div>
+          </div>
+        ) : (
          <ul className="dogsList">
            {posts.map((post, i) => {
              return (
                <li key={i} className="dogCard">
                  <img src={post} alt="犬の画像" className="dogImg" loading="lazy" />
                  <img src={ssrImg} alt="SSRラベル" className="ssrImg" />
                </li>
+              );
            })}
          </ul>
+        )}
        <input
          type="button"
          value="もう一回!"
          onClick={() => setRenew((renew) => renew + 1)}
          className="showRenewButton"
        />
      </div>
    </SDogCard>
  );
};

ローディングのぐるぐるが欲しかったので追加しました。

ローディングは下記サイト様を参考にさせていただきました。ありがとうございます!

完成

これで完成です。
あとは好きなだけガチャを回してください!

ちなみにレスポンシブ対応しているので、スマホでも回せます!やったね!

スクリーンショット_20221205_165356.png

おわりに

ここまで読んでいただきありがとうございました!
ボーナスとしてうちの犬の写真を置いておきます。

DSC_3940.JPG

かわい~~~~~~ッッッッッ!!!!

59
28
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
59
28

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?