編集メモ
下記の機構をちゃんと理解する必要がある
- サーバーサイドレンダリング - Next.js
- 非同期処理 - async/await ES6
- props - React.js
たかがgetとpostするだけなのに超ハマった。他にもハマっている人いるんじゃないかなぁと思うので、備忘録と言いつつ解説とか加えてます。
ただ、正しくない書き方の可能性が高いので、そこは自己責任で。。
githubのアカウントがあればNext.jsの学習サイトで触るうえでの知識が得られたのでお勧めです(fetchの動かし方とかこのサイト読まないとわからんでしょと正直思いました githubのREADME.mdに書いてありました。ちゃんと読めって話ですね・・)。
URLは一番下にリンク張っています。
前提とか
- server側にはrailsアプリを使ってますが必須ではないです
-
isomorphic-unfetch
プラグインが必要です
component側
getとpostをFetchClientという自作classにまとめてcomponentとして扱う
import fetch from 'isomorphic-unfetch'
class FetchClient{
static get(page, url, key = 'objects') {
const body = null
FetchClient.common('get', page, url, body, key)
}
static post(page, url, body, key = 'objects') {
const stringified_body = JSON.stringify(body)
FetchClient.common('post', page, url, stringified_body, key)
}
static common(method, page, url, body, key = 'objects'){
page.getInitialProps = async function (){
// アプリごとに変える必要があるのでheaders引数必要かも
const headers = {
'Content-Type': 'application/json'
}
const res = await fetch(url, {
method,
headers,
body
})
const data = await res.json()
// デバッグ用
console.log(data)
console.log(`Show data fetched. Count: ${data.length}`)
return {
[key]: data
}
}
}
}
export default FetchClient
getInitialProps
というNext.jsが提供しているメソッドを使うのがポイントっぽいです。
ページをconstとして造り、そのconstに対してこのメソッドを使用するとpropsをセットできるっぽい。名前はgetとなっているけどsetしてるっぽい。
これを知らないと多分ハマる、かも。
ちなみに、他のコンポーネントから呼ぼうと試行錯誤してみましたが呼び出せませんでした。
公式にはこう書かれています
Note: getInitialProps can not be used in children components. Only in pages
Google翻訳: 注:子コンポーネントではgetInitialPropsを使用できません。 ページ内のみ
となっているので、そもそも無理そうです。なので、このFetchClientコンポーネントは他のコンポーネントから直接呼び出すのではなく、page経由で間接的に使用するしかなさそうです。
pages側
それぞれ単体のメソッドを呼び出すだけのpageを作成
get
ページにアクセスした際にmessagesエンドポイントにgetを行い、response bodyの配列をリストにして表示するだけのpage
DBの状態
- 三件のmessages
[65] pry(main)> Message.all
Message Load (1.2ms) SELECT "messages".* FROM "messages"
=> [#<Message:0x00007f4c70b40078
id: 1,
text: "Good morning",
created_at: Tue, 17 Oct 2017 11:13:31 UTC +00:00,
updated_at: Tue, 17 Oct 2017 11:13:31 UTC +00:00>,
#<Message:0x00007f4c70b57ea8
id: 2,
text: "Good afternoon",
created_at: Tue, 17 Oct 2017 11:13:31 UTC +00:00,
updated_at: Tue, 17 Oct 2017 11:13:31 UTC +00:00>,
#<Message:0x00007f4c70b57d40
id: 3,
text: "Good evening",
created_at: Tue, 17 Oct 2017 11:13:31 UTC +00:00,
updated_at: Tue, 17 Oct 2017 11:13:31 UTC +00:00>]
[66] pry(main)>
コード
import React from 'react'
import Link from 'next/link'
// 自作component
import FetchClient from '../../components/code_test/FetchClient'
const FetchGet = (props) => (
<div>
<ul>
{props.messages.map(
message => (
<li key={message.id}>
<Link as={`/p/${message.id}`} href={`/post?id=${message.id}`}>
<a>{message.text}</a>
</Link>
</li>
)
)}
</ul>
</div>
)
FetchClient.get(FetchGet, 'http://localhost:3000/messages', 'messages')
export default FetchGet
ブラウザでアクセス
post
ページにアクセスした時点で決め打ちの'test'という文字列をmessageエンドポイントにpostし、response bodyの中からidやらtextやらを抜き出してtableに表示するだけのpage
DBの状態(getの時と同じ):before
[65] pry(main)> Message.all
Message Load (1.2ms) SELECT "messages".* FROM "messages"
=> [#<Message:0x00007f4c70b40078
id: 1,
text: "Good morning",
created_at: Tue, 17 Oct 2017 11:13:31 UTC +00:00,
updated_at: Tue, 17 Oct 2017 11:13:31 UTC +00:00>,
#<Message:0x00007f4c70b57ea8
id: 2,
text: "Good afternoon",
created_at: Tue, 17 Oct 2017 11:13:31 UTC +00:00,
updated_at: Tue, 17 Oct 2017 11:13:31 UTC +00:00>,
#<Message:0x00007f4c70b57d40
id: 3,
text: "Good evening",
created_at: Tue, 17 Oct 2017 11:13:31 UTC +00:00,
updated_at: Tue, 17 Oct 2017 11:13:31 UTC +00:00>]
[66] pry(main)>
コード
import React from 'react'
// 自作component
import FetchClient from '../../components/code_test/FetchClient'
const FetchPost = (props) => (
<div>
<table>
<thead>
<tr>
<th>id</th>
<th>text</th>
<th>created_at</th>
</tr>
</thead>
<tbody>
<tr>
<td>{props.created_record.id}</td>
<td>{props.created_record.text}</td>
<td>{props.created_record.created_at}</td>
</tr>
</tbody>
</table>
</div>
)
const body = {"text": "test"}
FetchClient.post(FetchPost, 'http://localhost:3000/messages', body, 'created_record')
export default FetchPost
ブラウザでアクセス
DBの状態:after
[68] pry(main)> Message.all
Message Load (1.7ms) SELECT "messages".* FROM "messages"
=> [#<Message:0x00007f4c70c201c8
id: 1,
text: "Good morning",
created_at: Tue, 17 Oct 2017 11:13:31 UTC +00:00,
updated_at: Tue, 17 Oct 2017 11:13:31 UTC +00:00>,
#<Message:0x00007f4c70c20010
id: 2,
text: "Good afternoon",
created_at: Tue, 17 Oct 2017 11:13:31 UTC +00:00,
updated_at: Tue, 17 Oct 2017 11:13:31 UTC +00:00>,
#<Message:0x00007f4c70c3be78
id: 3,
text: "Good evening",
created_at: Tue, 17 Oct 2017 11:13:31 UTC +00:00,
updated_at: Tue, 17 Oct 2017 11:13:31 UTC +00:00>,
#<Message:0x00007f4c70c3bd38
id: 30,
text: "test",
created_at: Sun, 07 Jan 2018 11:29:17 UTC +00:00,
updated_at: Sun, 07 Jan 2018 11:29:17 UTC +00:00>]
[69] pry(main)>
途中のIDが飛んで30になっていますが試行錯誤の名残なので気にしないでください。
4件目が登録されている、post成功。
参考にしたwebページ
-
github - Next.js
- リポジトリ
-
Learning Next.js
- Next.jsの学習サイト
- Qiita - ES2015以降のJavaScriptでObjectのkeyに変数を使う
- Qiita - fetch API でも POST したい!
-
Qiita - ES2015 (ES6)についてのまとめ
- classの参考にさせていただきました
まとめ
-
getInitialProps
を使う事
とりあえずhttps://learnnextjs.com/ を読んだ方が良いですね。。
変な箇所があれば教えてもらえると大変助かります!