Amplify SNS Workshopをやってみて気付いたことのメモ。説明は書いてくれてあるけど、それ以外でメモっておきたいこと。Reactの書き方についてが主なので慣れてる人にとっては何にもならない情報。
3.5 Post機能 Front-end
Sidebar, PostList ⊂ AllPosts, PostsBySpecifiedUser みたいな構造
Sidebar.js
(左側) + PostList.js
(右側) = AllPosts.js
or PostsBySpecifiedUser
(全体)
ただし、PostListは以下のようなpropsを持ち、postの取得自体はAllPosts or PostsBySpecifiedUserで行なっている。
const PostList = ({ isLoading, posts, getAdditionalPosts, listHeaderTitle, listHeaderTitleButton }) => {...}
App.js
ではRouterでAllPostsかPostsBySpecifiedUserを指定されたパスによって表示
function App() {
const classes = useStyles();
return (
<div className={classes.root} >
<ThemeProvider theme={theme}>
<CssBaseline />
<HashRouter>
<Switch>
<Route exact path='/' component={AllPosts} />
<Route exact path='/global-timeline' component={AllPosts} />
<Route exact path='/:userId' component={PostsBySpecifiedUser}/>
<Redirect path="*" to="/" />
</Switch>
</HashRouter>
</ThemeProvider>
</div>
);
}
userId
はPostsBySpecifiedUser
内部でuseParams()
で取得可能
Drawerは左側のメニューみたいな部分
Sidebar.js
のメニュー部分はmaterial-uiのDrawerコンポーネント
@auth
のownerFieldがあるおかげで、createpostするときにcognito identity(ユーザーID)が自動で挿入されてくれる
schema.graphql
のディレクティブの話。クエリで特にユーザーIDを指定していないのにDynamoDBにはちゃんと入っていたのはこのせいみたい。
useEffect()
の最後のreturnはクリーンアップと言って、コンポーネントが画面から消える時に実行されるReactの機能っぽい
5.3 Timeline機能 Back-end
Follow/Timelineの時にLambdaリゾルバ によりPostテーブルへ作成することにしてる。多分処理が複雑になってフロントエンド でいじるよりかはこっちで共通処理作ったほうが楽だからだろう
@connection
でのリレーション
schema.graphql
のディレクティブの話。Timelineオブジェクトのこの部分↓で、指定したpostIdをidにもつpostを持ってこられる。クエリの時にはpostIdを指定するだけでいい。
postId: ID!
post: Post @connection(fields: ["postId"])
Lambdaリゾルバを呼び出すMutationを追加
引数がcontent, 返り値がPost型
type Mutation
{
createPostAndTimeline(
content: String!
): Post
@function(name: "...")
5.4 Timeline機能 @function
Lambda 関数内での処理について。
-
export default = object;
している場合にはrequire('object').default
にしないといけないらしい。 - LambdaにAppSyncから渡されるeventデータの構造はこのdocument
- createPostするたびに全てのfollowerのタイムラインに順次投下。
- Promise.allで全部の結果が返ってくるまで待つ。
-
createTimelineForAUser()
は投稿された単一のpostをあるfolloweeのタイムラインテーブルに投下する。
const results = await Promise.all(followers.map((follower) => {createTimelineForAUser({follower: follower, post: post})}));
- Lambdaで使うgqlクエリは自動生成されたものをコピペした。もっといい方法はないんだろうか(なさそう
5.5 Timeline機能 Front-end
Timeline.js
ではuseEffect()
を二つ使っており、どちらが先に発動するかは読めないよう
if(!currentUser) return;
を入れ忘れてエラーが出ていた。
subscription
を作る方のuseEffect
(2個目の方)が実行された段階でcurrentUser
がnull
だった。そのあとcurrentUser
の状態が変わった時にもう一度処理が走り、計2回処理が走るようだ。
useEffect(() => {
const init = async () => {
const currentUser = await Auth.currentAuthenticatedUser();
setCurrentUser(currentUser);
getPosts(INITIAL_QUERY, currentUser);
}
init();
}, []);
useEffect(()=> {
if(!currentUser) return;
const subscription = ...
}, [currentUser])
Sidebar.js
のcreatePostAndTimeline
の引数
以下のような形式で間違えてinputを入れていたら、なぜかlambdaが実行すらされずトラシューが超大変だった(正しくは{content: value}
のみ)}。
const res = await API.graphql(graphqlOperation(createPostAndTimeline, {input:{content: value}}))
手動でonにしたappsyncのログ(成功時(上記のinputを無くした時))
GraphQL Query: mutation CreatePostAndTimeline($content: String!) {
createPostAndTimeline(content: $content) {
type
id
content
owner
timestamp
}
}
, Operation: null, Variables: {
"content": "test11"
}
inputがあったときのログ(lambdaが実行されず失敗)。variablesが違うだけ。
Query: mutation CreatePostAndTimeline($content: String!) {
createPostAndTimeline(content: $content) {
type
id
content
owner
timestamp
}
}
, Operation: null, Variables: {
"input": {
"content": "test11"
}
}