はじめに
今回は問題集:初心者編の「APIからデータを取得してリスト表示するコンポーネント」を作成していきます。
Rails
まずRailsで「Post」というモデルと、APIを作成していきます。
モデル
DBに「Post」というモデルを作成します。
カラムは「title」「content」を用意します。
rails g model Post title:string content:text
作成したらDBに反映します。
rails db:migrate
コントローラー
次にAPI用にコントローラーを作成します。
rails g controller Posts
コントローラーはフロントエンドや外部アプリからのリクエスト(一覧取得、作成、更新など)を受け取って、適切なモデル操作を行い、レスポンスを返すもの。
今回はPostというデータベースにフロントエンド側からAPIでアクセスして一覧を取得します。
なので、外部APIとの通信や単純なファイルの返却、セッション管理のみが目的のときなど、DBに保存・取得が不要な処理を行う際は、モデルを作らずにコントローラーのみ作成することもあります。
コントローラーを作成したら処理を記述していきます。
# controllers/posts_controller.rb
class PostsController < ApplicationController
def index
render json: Post.all
end
end
1つ1つ解説していきます。
render json: Post.all
Postテーブルにあるデータを全て取得して、
APIレスポンスとしてJSON形式で返しています。
Post.all
で全データ取得して、
render json: データ
JSON形式に変換して、APIレスポンスとして返しています。
posts = Post.all
render json: posts
これでもOK
routes
次にroutesを設定していきます。
# config/routes.rb
resources :posts, only: [:index, :create]
これはRailsのルーティングを「投稿一覧取得」と「投稿作成」のみに限定しています。
なぜかというと他の不要なルート(編集や削除など)は作られないため、セキュリティや管理の面でいいみたいです。
(投稿作成は番外編で追加予定です。)
これでRails側は完了です。
React
次にReact側を作成していきます。
componentsフォルダに「PostList.jsx」というコンポーネントを作成してこちらに記述していきます。
PostList.jsx
import { useEffect, useState } from "react"
import axios from "axios"
const PostList = () =>{
const [posts,setPosts] = useState([]);
const fetch = async () =>{
try {
const res = await axios.get("http://127.0.0.1:3000/posts",{
headers: {
"Content-Type": "application/json"
},
withCredentials: true
})
setPosts(res.data)
} catch(err) {
console.error("投稿の取得に失敗しました:", err);
}
}
useEffect(()=>{
fetch()
},[])
return (
<>
<ul className="postList">
{posts.map((post)=>(
<li key={post.id}>title:{post.title}<br/>content:{post.content}<br/>--------------------</li>
))}
</ul>
</>
)
}
export default PostList
1つ1つ解説していきます。
APIからデータ取得
const fetch = async () => {
これは非同期関数の宣言です。
asyncをつけることでこの関数の中でawaitを使って非同期処理を待つことができます。
つまり待機所?
基本的にAPIリクエストなどの時間がかかる処理はasync/awaitを使って書くようです。
try {
try-catch構文
通信の成功/失敗それぞれの処理を分岐しています。
const res = await axios.get("http://127.0.0.1:3000/posts ",{
axios.get()でGETリクエストを送って、awaitでレスポンスを待っています。
URLの記述は超要注意!!!!
僕は「"http://127.0.0.1:3000/posts/ "」と書いてエラーに散々悩まされ、CORSエラーだのAxiosのリクエストエラーだのRails側のエラーだの、散々調べた結果URLの末尾にある「/」を削除するだけで解決しました。
headers: { "Content-Type": "application/json" },
リクエストヘッダーの設定です。
「このリクエストのボディ(本文)はJSON形式ですよ」ということをサーバーに伝えています。
APIを使った通信をする場合は必須!!!!
withCredentials: true
これはCookie(セッション情報)を一緒に送る指示です。
ログイン状態をRails側でセッション管理している場合、Cookieが必要になるため、これがないとログインしていても認証されません。
別の問題集でCookieを使用しており、エラーが発生したため記述しています。
setPosts(res.data);
用意した「setPosts」に取得した投稿データを渡しています。
これによって、画面に投稿一覧が表示される状態に更新されます。
useEffect()
useEffect(()=>{
fetch()
},[])
useEffectとは?
副作用(画面の描画以外の処理)を実行するための関数です。
例えば、
- データの取得
APIを呼び出す - イベントの登録
スクロール検知など - タイマー処理
setTimeout / setIntervalなど - クリーンアップ処理
イベント解除など
今回はAPIを呼び出しているため、useEffect内で先ほど作成したfetchを実行しています。
これにより、コンポーネントが表示されたときに自動的に投稿一覧を読み込みます。
出力
return (
<>
<ul className="postList">
{posts.map((post)=>(
<li key={post.id}>title:{post.title}<br/>content:{post.content}<br/>--------------------</li>
))}
</ul>
</>
)
最後に出力を行います。
ここは以前解いた問題と似たような処理になっているので説明は省きます。
まとめ
正直自分の力だけで解くことは難しくなってきました。
なのでGPTえもんの力を借りて、出てきたコード1つ1つの処理を理解できるように、ひたすら調べて・質問するなど深掘りして、こうやって記事を書くことで自分の中でまとめ理解を深めていっています。
もっといい勉強方法があればぜひ教えて欲しいです。
ただ、結局はひたすら手を動かすことで覚えていくのかなぁ。と思っているので、自力で調べる労力をAIに任せているってだけであとは書くのみ!って感じですかね?
次回は、「Userモデルを作成して、email, password_digestを持たせる」「SessionControllerを作成して、emailとpasswordでログインできるAPIを実装」の2本立てです!
ではまた。
自分用メモ
モデルとテーブルの関係性
- テーブル
データベースに保存されているデータをまとめているのがテーブル? - モデル
通常SQL言語を使ってデータベースとやり取りするのを、モデルを経由することによってデータベースとのやり取りが簡略化されSQLを記述しなくてもデータのやり取りができる。
モデルの命名規則
テーブルのデータ型