[Amplify + Next.js] 簡単な掲示板を作成
2021-08-22IT記事,Next.jsAWS Amplify,Next.js
前にReactで作った掲示板をNextにしてみる。SSRをまず使ってみる。
nextでプロジェクトを作成
npx create-next-appamplify init
? Enter a name for the project nextamplify1
The following configuration will be applied:
Project information
| Name: nextamplify1
| Environment: dev
| Default editor: Visual Studio Code
| App type: javascript
| Javascript framework: react
| Source Directory Path: src
| Distribution Directory Path: build
| Build Command: npm.cmd run-script build
| Start Command: npm.cmd run-script start
? Initialize the project with the above configuration? No
? Enter a name for the environment dev
? Choose your default editor: Visual Studio Code
? Choose the type of app that you're building javascript
Please tell us about your project
? What javascript framework are you using react
? Source Directory Path: src
? Distribution Directory Path: .next <<===== ここ
? Build Command: npm.cmd run-script build
? Start Command: npm.cmd run-script start
Using default provider awscloudformation
? Select the authentication method you want to use: AWS profile
今のcliのバージョンなら認識するかもしれないが、自分のときは Distribution Directory Path がbuildになったので、.nextに変更する。上記の部分。
Githubとの連帯とデプロイ
githubにレポジトリを作って、ブラウザでamplify consoleにアクセスして、Githubと連帯する。
このとき、設定を追加する項目で、nextのバージョン : latestを追加する。
参考 : AWS AmplifyでNext.jsのISRを試してみる
https://dev.classmethod.jp/articles/amplify-next-js-isr/
ここまででnextをAmplifyでデプロイすることができた。
Amplify APIを追加
amplify add apiでAPIを追加。
amplify add apiamplify push
amplify pushライブラリをインストール
npm install aws-amplify @aws-amplify/ui-react_app.jsに以下を追加
import Amplify from 'aws-amplify';
import config from '../src/aws-exports';
Amplify.configure({
...config, ssr: true
});GraphQLスキーマを変更
GraphQLスキーマを変更してamplify pushする。前の記事参照
Nextコードを書いていく
indexページを移植
import { useState } from "react";
import { API, graphqlOperation, withSSRContext } from "aws-amplify";
import { byCreatedAt } from "../src/graphql/queries.js";
import { createComment, createThread } from "../src/graphql/mutations.js";
import Link from "next/link";
// SSR時にスレッド一覧を取得
export async function getServerSideProps(req) {
const { API } = withSSRContext(req);
const { data } = await API.graphql(
graphqlOperation(byCreatedAt, {
type: "t",
sortDirection: "DESC",
})
);
console.log(data);
return {
props: {
threadList: data.byCreatedAt.items,
},
};
}
function Index(props) {
const [threadList, setThreadList] = useState(props.threadList);
const formFirstValue = { title: "", firstComment: "" };
const [formState, setFormState] = useState(formFirstValue);
// フォームをクリック時の動作
const onSubmitForm = async (e) => {
e.preventDefault();
// フォームが空なら終了
if (!formState.title || !formState.firstComment) return;
// スレッドとコメントの作成
const newThread = await createNewThread();
await createFirstComment(newThread.id);
setFormState(formFirstValue);
// 画面に反映
setThreadList([newThread, ...threadList]);
};
// スレッドの作成
const createNewThread = async () => {
const newThread = { title: formState.title, type: "t" };
const { data } = await API.graphql(
graphqlOperation(createThread, { input: newThread })
);
console.log(data);
return data.createThread;
};
// 最初のコメントを作成
const createFirstComment = async (threadId) => {
const newComment = { threadId: threadId, title: formState.firstComment };
const { data } = await API.graphql(
graphqlOperation(createComment, { input: newComment })
);
console.log(data);
};
// フォームに入力時、formStateを更新する
const onChange = (event, propaty) => {
setFormState({ ...formState, [propaty]: event.target.value });
};
return (
<div>
<div>掲示板(Amplify + Next)</div>
<div>
{threadList.map((thread, index) => {
return (
<div key={index}>
<Link href={"/" + thread.id}>
<a>{thread.title}</a>
</Link>
</div>
);
})}
</div>
<div>
<form>
<div>
<div>
<label htmlFor="threadTitle">スレッドタイトル</label>
</div>
<input
id="threadTitle"
value={formState.title}
onChange={(event) => onChange(event, "title")}
></input>
</div>
<div>
<div>
<label htmlFor="threadFirstComment">最初のコメント</label>
</div>
<input
id="threadFirstComment"
value={formState.firstComment}
onChange={(event) => onChange(event, "firstComment")}
></input>
</div>
<button onClick={onSubmitForm}>送信</button>
</form>
</div>
</div>
);
}
export default Index;
threadページ
import { API, graphqlOperation, withSSRContext } from "aws-amplify";
import { useEffect, useState, useRef } from "react";
import { createComment } from "../src/graphql/mutations";
import { getThread } from "../src/graphql/queries";
import { onCommentByThreadId } from "../src/graphql/subscriptions";
import { useRouter } from "next/router";
// SSRでスレッド情報を取得
export async function getServerSideProps(req) {
const { API } = withSSRContext(req);
const { data } = await API.graphql(
graphqlOperation(getThread, { id: req.params.threadId })
);
console.log(data);
return {
props: {
thread: data.getThread,
},
};
}
export default function Thread(props) {
const router = useRouter();
const { threadId } = router.query;
const [thread, setThread] = useState(props.thread);
const [commentForm, setCommentForm] = useState({ title: "" });
const subscriptionRef = useRef();
// サブスクを設定する
useEffect(() => {
attachSubscription();
return () => {
if (subscriptionRef) subscriptionRef.current.unsubscribe();
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
// subscriptionを設定
const attachSubscription = () => {
subscriptionRef.current = API.graphql(
graphqlOperation(onCommentByThreadId, { threadId: threadId })
).subscribe({
next: (data) => {
console.log(data);
addComment(data.value.data.onCommentByThreadId);
},
error: (error) => console.warn(error),
});
};
// コメントのリストに新たに追加
const addComment = (newComment) => {
setThread((thread) => {
// リスト内に既にあったら追加しない
const idx = thread.comments.items.findIndex(
(comment) => comment.id === newComment.id
);
if (idx !== -1) return thread;
console.log("update comment list", thread);
return {
...thread,
comments: { items: [...thread.comments.items, newComment] },
};
});
};
// フォーム送信時
const onSubmit = async (e) => {
e.preventDefault();
if (!commentForm.title) return;
const newComment = await createNewComment();
setCommentForm({ title: "" });
// thread情報の更新
setThread((thread) => {
return {
...thread,
comments: { items: [...thread.comments.items, newComment] },
};
});
};
// コメントの作成
const createNewComment = async () => {
const { data } = await API.graphql(
graphqlOperation(createComment, {
input: { threadId: threadId, title: commentForm.title },
})
);
console.log(data);
return data.createComment;
};
return (
<div>
<h1>{thread.title}</h1>
{thread.comments.items.map((comment, idx) => {
return <div key={idx}>{comment.title}</div>;
})}
<div>
<form>
<div>
<label htmlFor="commentForm">コメント</label>
</div>
<input
id="commentForm"
value={commentForm.title}
onChange={(event) => setCommentForm({ title: event.target.value })}
></input>
<button onClick={onSubmit}>送信</button>
</form>
</div>
</div>
);
}

動いた。ヤッター。
サイト公開アドレス :
https://main.d1xvmlla5wn67x.amplifyapp.com/
公式ドキュメント
AWS AmplifyJavaScriptライブラリのSSRサポート
https://aws.amazon.com/jp/blogs/mobile/ssr-support-for-aws-amplify-javascript-libraries/
AWSAmplifyでリアルタイムデータを使用してNext.jsSSRアプリをホストします
https://aws.amazon.com/jp/blogs/mobile/host-a-next-js-ssr-app-with-real-time-data-on-aws-amplify/
HOSTING Next.js
https://docs.amplify.aws/guides/hosting/nextjs/q/platform/js#adding-amplify-hosting-1
関連記事

[AWS Amplify] API(Graphql)のパブリック設定。複数認証。subscriptionまで。
前回公開したアプリでは、ログインした人たちが投稿と投票をできて、ログインしていな ...

[ AWS Amplify + Vue.js ] Authでログイン画面作る
この記事では AWS Amplify の@aws-amplify/ui-vueを ...

[AWS Amplify] ログイン画面を日本語化する
まずプラグインを公開してくれている方がいるので、こちらを使います。 npm in ...

100日後まであと何日か表示する Webアプリを作ってみた [AWS Amplify]
100日後に死ぬワニを見ていると、今この文章を書いたり読んだりしている自分こそワ ...

Next 13 + Tilewind に Storybook 7 インストール
記事日付 2023/02/18 環境 Windows11 (WSL) "next ...
ディスカッション
コメント一覧
488bet777. Big numbers, big potential, right? I’m hoping for some decent odds here. Let’s roll! 488bet777
Winer is not my favorite, honestly. Too many redirects and loading times. Not gonna lie, but you guys might like it! Check it here: winer
8win55 is my go-to. Big selection of games, promotions are actually pretty good. Give it a try. 8win55