【React로】 소설 투고 사이트 등에 자주 있는 「전 ○ 이야기」같은 것을 표시시키는 방법
소개
이번은 소설 투고 사이트 등에 자주 있는 「전○화」를 자작 어플에서 표시시키는데 상당히 고생했다(3일 걸렸다) 때문에, 계명으로서 남겨 두고 싶습니다.
실현하고 싶은 일
「シリーズ」
라는 폴더적인 역할을 가지는 모델과 「アイテム」
ルートページ
에서 「시리즈」전건을 표시시켜, 그 「シリーズ」が所有する「アイテム」を全て取得し、その総数をカウント
시켜 「全〜件」という形で表示
시키고 싶다. 고생한 이유
ルートページ
이었기 때문입니다. 보통이라면 各シリーズが所有するアイテム
를 얻으려고 하는 경우, 예를 들어 URL이 "/series/104"
라면, 시리즈의 파라미터(이 경우라면 104)를 취득해, 그 파라미터를 의지해 아이템을 취득합니다. 그래서 그래서, 파라미터가 존재하지 않는 루트 페이지에서 어떻게 각 시리즈의 파라미터를 취득하면 옳은 느낌과 중반 깨어 가면서 생각하고 있었던 것입니다(지금 생각하면 단순한 이야기였습니다)
환경·전제 등
환경
프런트 엔드
백엔드
전제
Rails 측
컨트롤러
Api::V1::SeriesController
라우팅
"/"
→ "api/v1/series#index"
"api/v1/item_count/:series_id"
→ "api/v1/series#item_count"
React측
Homeコンポーネント
: 시리즈를 전건 취득하고 Series라는 컴퍼넌트에 각 데이터를 순차적으로 전달하는 역할을 갖게 한다. Seriesコンポーネント
: 이 컴포넌트로 각 시리즈를 표시시킨다. ItemCountコンポーネント
: 각 시리즈가 가지는 아이템의 총수만을 표시시킨다. useFetchカスタムフック
: Rails에서 데이터를 가져옵니다. Rails 측 코드
라우팅
routes.rb
Rails.application.routes.draw do
# ルート
root to: 'api/v1/series#index'
# アイテムのカウント
get 'api/v1/item_count/:id', to: 'api/v1/series#item_count'
end
컨트롤러
app/controller/api/v1/series_controller.rb
class Api::V1::SeriesController < ApplicationController
# item_countアクションに、パラメータから取得したシリーズをコールバック
before_action :set_series, only: [:item_count]
def index
@series =Series.all
render json: {
status: 200,
series: @series,
keyword: "index_of_series" # React側で使う
}
end
def item_count
@items = @series.items.all # シリーズに関連付けられているアイテムの取得
@items_count = @items.count # アイテムの総数をカウント
render json: {
status: 200,
item_count: @item_count, # カウントをJSONとしてReactへ送信
keyword: "item_count" # React側で使う
}
end
private
# パラメータを頼りにシリーズを取得
def set_series
@series = Series.find(params[:id])
end
end
React 측 코드
// 階層
//src
// ├ Home.js
// ├ Series.js
// ├ ItemCount.js
// └ useFetch.js
useFetch 사용자 정의 후크
src/useFetch.js
import { useState, useEffect } from "react"
import axios from 'axios'
// カスタムフックでは文頭はuseが必須
// useFetchの引数に、methodとurlを渡す
// これは、HomeとItemCountコンポーネントにて、Railsとの通信に使う
// HTTPリクエストと、ルーティングを指定するため
export default function useFetch({method, url}) {
// 初期値の定義。
const [items, setItems] = useState("")
useEffect(() => {
const getItems = () => {
// ここのmethodとurlにて、Home・ItemCountコンポーネントから
// 送られてくるメソッドとルーティングを代入することになる。
axios[method](url)
.then(response => {
let res = response.data
let ok = res.status === 200
// シリーズ全件取得
// Rails側で指定したkeywordはここで使う。
// そうしてカウントとの区別を付けている。
if (ok && key === 'index_of_series') {
setItems({ ...res.series })
// シリーズごとのアイテムの総数を取得
} else if (ok && key === 'item_count') {
setItems(res.item_count)
}
})
.catch(error => console.log(error))
}
getItems()
}, [method, url, items])
return {
items // items変数を他のコンポーネントで使えるようにする。
}
}
Home 구성 요소
src/Home.js
import React from 'react'
import Series from './Series'
import useFetch from './useFetch'
function Home() {
// ここでは、useFetchからRailsで取得したシリーズのデータを受け取っている。
// methodはget、urlはRailsのルートのURLを指定。これにより、
// useFetchからRailsのルートのルーティングへリクエストが送信され、
// その後Railsから受け取ったデータをitemsへ格納します。
const { items } = useFetch({
method: "get",
url: 'http://localhost:3001'
})
return (
<div>
{/* Object.keys()メソッドを使い、JSONで送られてくるitemsを */}
{/* ループ処理で1個ずつSeriesコンポーネントに渡している。 */}
{/* JSONは、{ {...}, {...}, {...} }のようなものであると想定 */}
{Object.keys(items).map(key => (
<Series key={key} items={items[key]} />
))}
</div>
)
}
export default Home
Series 구성 요소
src/Series.js
import React from 'react'
import ItemCount from './ItemCount'
function Series(props) {
// Homeから送られてくるpropsを頼りに、各シリーズのidをここで取得しています。
// このidをパラメータとして使うことで、各シリーズの所有するアイテムにアクセスすることができます。
const seriesId = props.items.id
const seriesTitle = props.items.title
return (
<div>
<div>{seriesTitle}</div>
{/* ItemCountコンポーネントに、シリーズのidを渡す。 */}
<ItemCount {...props} seriesId={seriesId} />
</div>
)
}
export default Series
ItemCount 구성 요소
src/ItemCount.js
import React from 'react'
import useFetch from './useFetch'
function SeriesCount(props) {
// useFetchを使いRailsと通信。
// methodはget、urlはRailsの`api/v1/item_count/${props.seriesId}`を指定。
// id部分にSeriesコンポーネントから渡ってくる各シリーズのidを嵌め込むことで、
// Railsの"api/v1/item_count/:id"というルーティングへリクエストが送信され、
// その後Railsから各シリーズの持つアイテムのカウント数を受け取り、最後にitemsへ格納されます。
const { items } = useFetch({
method: 'get',
url: `http://localhost:3001/api/v1/item_count/${props.seriesId} `
})
return (
<div>
{/* Railsから送られてくるアイテムの総数をここにレンダリングします。 */}
(このシリーズは全部で {items} 個のアイテムを所有しています)
</div>
)
}
export default SeriesCount
Reference
이 문제에 관하여(【React로】 소설 투고 사이트 등에 자주 있는 「전 ○ 이야기」같은 것을 표시시키는 방법), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/kurawo___D/items/86daf210b8ef16d69c9d텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)