Amplifyの公式ワークショップをなぞったメモ

[Amplify SNS Workshop](https://amplify-sns.workshop.aws/ja/10_getting_started/00_what_you_build.html)をやってみて気付いたことのメモ。説明は書いてくれてあるけど、それ以外でメモっておきたいこと。Reactの書き方についてが主なので慣れてる人にとっては何にもならない情報。

## [3.5 Post機能 Front-end](https://amplify-sns.workshop.aws/ja/30_mock/30_post_front_end.html)

#### 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を指定されたパスによって表示
```javascript
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](https://amplify-sns.workshop.aws/ja/50_follow_timeline/20_timeline_back_end.html)
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](https://amplify-sns.workshop.aws/ja/50_follow_timeline/30_function_directive.html)
Lambda 関数内での処理について。

- `export　default = object;`している場合には`require('object').default`にしないといけないらしい。
- LambdaにAppSyncから渡されるeventデータの構造は[このdocument](
https://docs.amplify.aws/cli/graphql-transformer/function/#structure-of-the-function-event)
- 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](https://amplify-sns.workshop.aws/ja/50_follow_timeline/50_timeline_front_end.html)

#### `Timeline.js`では`useEffect()`を二つ使っており、どちらが先に発動するかは読めないよう
`if(!currentUser) return;` を入れ忘れてエラーが出ていた。
`subscription`を作る方の`useEffect`(2個目の方)が実行された段階で`currentUser`が`null`だった。そのあと`currentUser`の状態が変わった時にもう一度処理が走り、計2回処理が走るようだ。

```javascript
  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}`のみ)}。

```javascript
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"
    }
}
```