LoginSignup
1
0

ReactとJavaScriptでAPIで記事データを取得してみた!その3

Last updated at Posted at 2024-06-21

はじめに

こんにちは!WEBエンジニア転職目指しているK.Yです!
今回は、APIでデータを取得して表示させる内容となります。

以下の記事は、手書きでデータを取得した内容となります!
良かったらこちらも読んでいただけると嬉しいです!
Reactの基本的な機能や特徴について記述しています!

前回の記事と重複している部分は省略しております!

対象者

・ React初心者
・ フロントエンドに興味がある人

バージョン

"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-router-dom": "^6.23.1"

JavaScript ES6以降

コード

PostsList

import React, { useEffect, useState } from 'react'
import './App.css'
import { Link } from 'react-router-dom';

const PostsList = () => {

  const formatDate = (dateString) => {
    const date = new Date(dateString);
    const options = { year: 'numeric', month: 'numeric', day: 'numeric' };

    return date.toLocaleDateString('ja-JP', options);
  };

  const [posts, setPosts] = useState({ articles: [] });
  const [loading, setLoading] = useState(true); // ローディング状態を追加

  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await fetch("https://1hmfpsvto6.execute-api.ap-northeast-1.amazonaws.com/dev/posts");
        const data = await response.json();

        setPosts( data );

      }  finally {
        setLoading(false); // データ取得が完了したらローディングを終了
      }
    };

    fetchData();
  }, []);

  if (loading) {
    return <div>Loading...</div>; // ローディング中の表示
  }

  return (
    <div className="App">
      <header className="header-App">
        <Link className="link" to="/">Blog</Link>
        <Link className="link" to="/">お問い合わせ</Link>
      </header>

      {
        Array.isArray(posts.posts) && posts.posts.map(article => (
          <div key={article.id} className="posts-info">
            <ul >
              <li>
                <Link to={`/post/${article.id}`}>
                  <div className="date">{formatDate(article.createdAt)}</div>
                  <div className="programming-language">{article.categories.map((category, idx) => (
                    <span key={idx} className="category-box">{category}</span>
                  ))}</div>
                  <div className="title">{article.title}</div>
                  <div className="content" dangerouslySetInnerHTML={{ __html: article.content }}>
                  </div>
                </Link>
              </li>
            </ul>
          </div>
        ))}
    </div>
  );

}

export default PostsList;
DetailsPage

const { id } = useParams();

  const formatDate = (dateString) => {
    const date = new Date(dateString);
    const options = { year: 'numeric', month: 'numeric', day: 'numeric' };
    return date.toLocaleDateString('ja-JP', options);
  }

  const [detailsData, setDetailsData] = useState();
  const [loading, setLoading] = useState(true); // ローディング状態を追加

  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await fetch(`https://1hmfpsvto6.execute-api.ap-northeast-1.amazonaws.com/dev/posts/${id}`);
        const result = await response.json();

        setDetailsData(result.post); 
      } finally {
        setLoading(false); // データ取得が完了したらローディングを終了
      }

    };

    fetchData();
  }, [id]);

  if (loading) {
    return <div>Loading...</div>; // ローディング中の表示
  }

  if (!detailsData) return <div>投稿が見つかりません</div>;

  return (
    <div className='App'>
      <header className="header-App">
        <Link to="/" className="link">Blog</Link>
        <Link to="/" className="link" >お問い合わせ</Link>
      </header>

        <div style={{ border: 'none' }} className="posts-info">
          <ul>
            <li key={detailsData.id}>
              <div><img src={detailsData.thumbnailUrl} alt="img" /></div>
              <div className="date">{formatDate(detailsData.createdAt)}</div>
              <div className="programming-language">
                {detailsData.categories.map((category, idx) => (
                  <span key={idx} className="category-box">{category}</span>
                ))}
              </div>
              <div className="title">{detailsData.title}</div>
              <div style={{ display: 'block' }} className="content" dangerouslySetInnerHTML={{ __html: detailsData.content }}></div>
            </li>
          </ul>
        </div>
    </div>
  );
}
export default DetailsPage;

API

APIとは、ソフトウェアアプリケーションが互いにやり取りを行うための仕組みです。
フロントエンド、バックエンドの連携において重要な役割を果たします。

APIはHTTPなどのプロトコルを用いて、リクエストやレスポンスのやり取りを行います。
リクエストには、データの取得や登録・削除・更新などの操作を支持する情報が含まれていて、
レスポンスは、データやエラーメッセージ’などの情報が含まれています。

PostsList(記事一覧ページ)

PostsList

import React, { useEffect, useState } from 'react'
import './App.css'
import { Link } from 'react-router-dom';

const PostsList = () => {

  const formatDate = (dateString) => {
    const date = new Date(dateString);
    const options = { year: 'numeric', month: 'numeric', day: 'numeric' };

    return date.toLocaleDateString('ja-JP', options);
  };

  const [posts, setPosts] = useState({ articles: [] });
  const [loading, setLoading] = useState(true); // ローディング状態を追加

  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await fetch("https://1hmfpsvto6.execute-api.ap-northeast-1.amazonaws.com/dev/posts");
        const data = await response.json();

        setPosts( data );

      }  finally {
        setLoading(false); // データ取得が完了したらローディングを終了
      }
    };

    fetchData();
  }, []);

  if (loading) {
    return <div>Loading...</div>; // ローディング中の表示
  }

  return (
    <div className="App">
      <header className="header-App">
        <Link className="link" to="/">Blog</Link>
        <Link className="link" to="/">お問い合わせ</Link>
      </header>

      {
        Array.isArray(posts.posts) && posts.posts.map(article => (
          <div key={article.id} className="posts-info">
            <ul >
              <li>
                <Link to={`/post/${article.id}`}>
                  <div className="date">{formatDate(article.createdAt)}</div>
                  <div className="programming-language">{article.categories.map((category, idx) => (
                    <span key={idx} className="category-box">{category}</span>
                  ))}</div>
                  <div className="title">{article.title}</div>
                  <div className="content" dangerouslySetInnerHTML={{ __html: article.content }}>
                  </div>
                </Link>
              </li>
            </ul>
          </div>
        ))}
    </div>
  );

}

export default PostsList;

ステートの設定

const [posts, setPosts] = useState({ articles: [] });
const [loading, setLoading] = useState(true); // ローディング状態を追加

useStateを使って、ステートを定義。
postsは、APIから取得したデータを格納するためのステートです。
初期値は{ articles: [] }(空の配列を含むオブジェクト)です。

setPostsは、postsステートを更新するための関数です。

loadingは、データがロード中であるかどうかを示すブール値のステートです。
初期値は、true

setLoadingは、loadingを更新するための関数です。

データ取得(useEffectフック)

useEffect(() => {
  const fetchData = async () => {
    try {
      const response = await fetch("https://1hmfpsvto6.execute-api.ap-northeast-1.amazonaws.com/dev/posts");
      const data = await response.json();

      setPosts(data);
    } finally {
      setLoading(false); // データ取得が完了したらローディングを終了
    }
  };

  fetchData();
}, []);

useEffectを使って、副作用(この場合はデータ取得)を実行します。
 useEffectの第二引数に空の配列[]を渡すことで、ページ読み込み時にデータを取得したい時に、用いる手法です。

fetchDataは非同期関数で、APIからデータを取得。

fetch関数を使って、指定されたURLからデータを取得。

awaitを使って、fetch関数が完了するのを待つ」。

response.json()を使って、取得したデータをJSON形式に変換します。

setPosts(data)を使って、取得したデータをpostsステートに保存。

loadingステートをfalseに設定します。

useEffectの中で、fetchData関数を呼び出して、データ取得を開始します。

loadingステートがtrueの間は、"Loading..."というメッセージを表示します。
 データ取得が完了してloadingステートがfalseになると、この部分はスキップされ、次の部分(投稿リストの表示)が実行。

DetailsPage.js (記事詳細ページ)

DetailsPage

const { id } = useParams();

  const formatDate = (dateString) => {
    const date = new Date(dateString);
    const options = { year: 'numeric', month: 'numeric', day: 'numeric' };
    return date.toLocaleDateString('ja-JP', options);
  }

  const [detailsData, setDetailsData] = useState();
  const [loading, setLoading] = useState(true); // ローディング状態を追加

  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await fetch(`https://1hmfpsvto6.execute-api.ap-northeast-1.amazonaws.com/dev/posts/${id}`);
        const result = await response.json();

        setDetailsData(result.post); 
      } finally {
        setLoading(false); // データ取得が完了したらローディングを終了
      }

    };

    fetchData();
  }, [id]);

  if (loading) {
    return <div>Loading...</div>; // ローディング中の表示
  }

  if (!detailsData) return <div>投稿が見つかりません</div>;

  return (
    <div className='App'>
      <header className="header-App">
        <Link to="/" className="link">Blog</Link>
        <Link to="/" className="link" >お問い合わせ</Link>
      </header>

        <div style={{ border: 'none' }} className="posts-info">
          <ul>
            <li key={detailsData.id}>
              <div><img src={detailsData.thumbnailUrl} alt="img" /></div>
              <div className="date">{formatDate(detailsData.createdAt)}</div>
              <div className="programming-language">
                {detailsData.categories.map((category, idx) => (
                  <span key={idx} className="category-box">{category}</span>
                ))}
              </div>
              <div className="title">{detailsData.title}</div>
              <div style={{ display: 'block' }} className="content" dangerouslySetInnerHTML={{ __html: detailsData.content }}></div>
            </li>
          </ul>
        </div>
    </div>
  );
}
export default DetailsPage;

データ取得(useEffectフック)

useEffect(() => {
  const fetchData = async () => {
    try {
      const response = await fetch(`https://1hmfpsvto6.execute-api.ap-northeast-1.amazonaws.com/dev/posts/${id}`);
      const result = await response.json();
      setDetailsData(result.post); 
    } finally {
      setLoading(false); // データ取得が完了したらローディングを終了
    }
  };

  fetchData();
}, [id]);

useEffectの第二引数に[id]を渡すことで、idが変わるたびにこの副作用が再実行されます。

tryブロック内で、データの取得と処理を行います。

finallyブロックで、データ取得が完了したら(成功しても失敗しても)loadingステートをfalseに設定します。

ポイント

副作用の管理APIを呼び出す処理
useEffectフックを使って、APIデータを取得などの副作用を管理。

・非同期処理 async/await
非同期処理は、時間のかかる操作(例えば、ネットワークリクエストやファイルの読み書きなど)をブロックせずに実行するために使用されます。JavaScriptでは、非同期処理を行うためにasync/awaitやPromiseを使う。

終わり

今回は、APIでデータ取得を実装してみました!
少しでもこの記事がお役に立てれば幸いです!
 次回は、問い合わせフォームの作成となります。
お楽しみに!

1
0
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
0