React始めたい


windows10
`react@17.0.1`
`aws-amplify@3.3.14`

# プロジェクトを作る　
npxで作成する [(公式)](https://ja.reactjs.org/docs/create-a-new-react-app.html#create-react-app)

```bash
npx create-react-app sukina-project-name
```

起動

```bash
cd sukina-project-name
npm start
```


# 画面(部品)の作成

1部品で1画面を作ることも可能。しかし、小さく作って組み合わせる方が再利用性が高くてスマート

作成した直後のプロジェクトの中にあるApp.jsのように、描画する画面を返す関数を定義するか、

```Welcome.js
// functionで描く
export default function Welcome() {
  return <h1>Hello World</h1>;
}
```

クラスを作ってrender関数で返す

```Welcome.js
import React from "react";

//class.renderで描く
export default class Welcome extends React.Component {
  render() {
    return <h1>Hello World</h1>;
  }
}
```

[(公式)](https://ja.reactjs.org/docs/components-and-props.html#function-and-class-components)


export defaultは下でもよい

```Welcome.js
class Welcome extends React.Component {
  render() {
    return <h1>Hello World</h1>;
  }
}
export default Welcome;
```

# 配列の中身を書きだしたい

```react

const values = [ 1, 2, 3 ]

return (
  {values.map( (v) => <div>{v}</div> ) }

  //{for(let v in values){ <div>{v}</div> }} 式は書けないのでこれは無理
)
```
や

```react
const values = [ 1, 2, 3 ]
let items = []
for(let v in values){ items.push( <div> {v} </div>) }

return (
  {items}
)
```



# 画面遷移したい

React Routerを使う。[(公式)](https://ja.reactjs.org/docs/code-splitting.html#route-based-code-splitting)

React Routerのインストール[(公式)](https://reactrouter.com/web/guides/quick-start)

```bash

npm install react-route-dom
```

ここでは例として、/todo というURLを指定した時に表示したいページを作っている
src直下にTodo.jsを作成

```src/Todo.js
// /todoでアクセスすると描画する内容
import React,{ Component } from 'react'

export default class Todo extends Component {
    render(){
        return <div> hello! </div>;
    }
}
```

BrowserRouter、Suspense、Switch、Routeコンポーネントを使って、表示先を選択する

インポート部分

```App.js

// React.lazyとReact.Suspenseをインポート
import React , {Suspense,lazy} from 'react';
import './App.css';

// React Routerからインポート
import {
  BrowserRouter as Router,
  Switch,
  Route
} from "react-router-dom";

// 前で作ったTodoクラスを取り込み
const Todo = lazy(() => import('./Todo')); 

```

Todo.jsをApp.jsにインポート

描画処理

```App.js 
function App() {
  return (
    <Router>
      <Suspense fallback={<div>Loading...</div>}>
        <Switch>
          <Route path="/todo" component={Todo} />
          <Route path="/">
            <h1>root</h1>
          </Route> 
        </Switch>
      </Suspense>  
    </Router>
  );
}
 
export default App; 
```

Router、Switch、Routeタグを使ってurlに対応するコンポーネントを切り替える

\<Suspense\>は、読みこみ中の間に表示する、ちょっと待ってね的表示。ここではLoading...と表示される
lazyで読み込んだコンポーネントを表示する場合は、\<Suspense\>の中で呼び出さないと、
A React component suspended while rendering, but no fallback UI was specified.といわれる。

Routeの書き方は以下のどちらも同じ意味

```react
<Route path="/todo" component={Todo} />
```

```react
<Route path="/todo">
  <Todo />
</Route>
```

## ボタンで画面遷移したい
Linkコンポーネントでボタンを囲むと、ボタンを押したとき画面遷移する

```react
import { Link } from 'react-router-dom'
```

```react
<Link to="/todo">
  <button>Login</button>
</Link>
```

というか、buttonに限らずlabelやspanなどでも画面遷移する


# UIライブラリ

いろいろあるので気に入ったものを使えばよいが、
困ったら標準的な部類ということで[material-ui](https://material-ui.com/)が良さそう

# フックとは
[公式](https://ja.reactjs.org/docs/hooks-overview.html#but-what-is-a-hook)

例えば、classを使って状態を保存する場合は[state](https://ja.reactjs.org/docs/state-and-lifecycle.html#adding-local-state-to-a-class)機能を使用する。
state等のreactが持つ機能を、クラスでは無くて関数で使うために（画面は[classでも関数でも作れるから](#画面部品の作成)用意された関数をフックという。
state機能を使うためのフックを[ステートフック](https://ja.reactjs.org/docs/hooks-overview.html#state-hook)という。

使用上の注意あり[(公式)](https://ja.reactjs.org/docs/hooks-overview.html#rules-of-hooks)。
・常にトップレベルで使う事。つまりif,forといった{}の中で使ってはいけない。
・reactコンポーネントの中だけで使用する。純粋なjavascript関数の中で使用してはいけない。
破ると動かない？予期しない動作となる？


# ユーザー認証、ユーザー登録をしたい(AWS Cognito , AWS Amplify)

サインアップ、サインインなどをしたい時。
自分でゴリゴリ実装するのではなくAWS Cognitoを使用するケース。
reactからAWS Cognitoを使用するには、AWS Amplifyを利用するのが早い。

## AWS Amplifyのインストールと初期の設定 [(公式)](https://docs.amplify.aws/lib/auth/getting-started/q/platform/js#configure-your-application)

amplifyを[インストール](https://docs.amplify.aws/cli/start/install)

初期設定の為、以下のコマンドをプロジェクトのルートで実行

```bash
amplify init
```

AWS Cognitoにユーザープール等を作る時、Amplifyを使って作る場合はコマンドから作成できる。[(公式)](https://docs.amplify.aws/lib/auth/start/q/platform/js#create-new-authentication-resource)
手動でユーザープール等AWSリソースを作る場合はこれらのコマンドは不要

```bash
amplify add auth

amplify push
```

amplify pushによりユーザープール等が作成される。
またamplify pushが完了すると、src直下に、作成したAWSリソースにアクセスするための情報が入ったaws-export.jsが作成される。↓

```src/aws-exports.js
//生成されたaws-exports.js *****にはユーザープール等の情報が設定されている

/* eslint-disable */
// WARNING: DO NOT EDIT. This file is automatically generated by AWS Amplify. It will be overwritten.

const awsmobile = {
    "aws_project_region": "*****",
    "aws_cognito_identity_pool_id": "*****",
    "aws_cognito_region": "*****",
    "aws_user_pools_id": "*****",
    "aws_user_pools_web_client_id": "*****",
    "oauth": {}
};

export default awsmobile;
```

手動で作った既存のAWS Cognitoリソースを使いたい場合は、
このaws-exports.jsの内容を、使いたい既存リソースのIDに変更する。[(公式)](https://docs.amplify.aws/lib/auth/start/q/platform/js#re-use-existing-authentication-resource)

### aws_cognito_identity_pool_idが分かりにくかったので確認方法をメモる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156655/d5be3236-1de6-d026-5be3-db84fd24b0e6.png)
Cognito入って直ぐ「IDプールの管理」

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156655/555cab84-dd80-cf6c-1e1c-512fe97e7c55.png)
IDプール名がリンクになっているのでクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156655/a05ae42b-6dfa-cee4-1bd3-5c3a815b36a4.png)
画面右上のIDプールの編集をクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156655/2894f514-692e-2d31-31d6-91d047548b0c.png)

IDプールのIDに書いてある文字列全部

Unable to verify secret hash for clientとか言われる時は、
アプリクライアントを追加する時に、「クライアントシークレットを生成」にチェックを入れている可能性がある。
この場合、「クライアントシークレットを生成」をチェックしない様にしてアプリクライアントを再登録する。（IDが新しくなるので変更する）
[AWS Cognito Identity NotAuthorizedException](https://stackoverflow.com/questions/37603822/aws-cognito-identity-notauthorizedexception)

## 非ログイン時、ページにダイレクトアクセスされたら認証に飛ばしたい

AmplifyAuthenticatorコンポーネントを使用する。[(公式)](https://docs.amplify.aws/ui/auth/authenticator/q/framework/react)
App.jsの描画処理で、\<AmplifyAuthenticator\>で囲むだけでOK

↓必要なインポート ([ルーティング分](#画面遷移したい)は除く)

```App.js
import Amplify from "aws-amplify";
import { AmplifyAuthenticator } from "@aws-amplify/ui-react"
import awsconfig from "./aws-exports";

Amplify.configure(awsconfig);
```

描画処理部分

```App.js
function App() {
  return (
    <AmplifyAuthenticator> //コレ

      <Router>
        <Suspense fallback={<div>Loading...</div>}>
          <Switch>
            <Route path="/test" component={Test} />
            <Route path="/" component={Home} />
          </Switch>
        </Suspense>
      </Router>

    </AmplifyAuthenticator>
  );
}
```

ルーティングで、/test と /　の時が定義しているが、
ログインしていない時は、/test と /　のどちらにアクセスしても認証フォームが表示される。