【Firebase】Firebase + React で作るTodoリストハンズオン

## 概要
今回から複数回に分けてFirebaseとReactを用いたTodoリストをハンズオン形式で１から説明していこうと思います！
初心者の方でもわかるように比較的丁寧に解説しているのでぜひ手を動かして作って見てください！！

## 目次
[Reactプロジェクトの立ち上げ](https://qiita.com/yousuke_1112/items/720dcfbae1650556f112)←今回
[Firebaseの初期化](https://qiita.com/yousuke_1112/items/948021e4f037855e49a0)
[FireAuth+FireStore]()
[Todoリストの作成]()


## 前提
ご自身のパソコンに、Node.jsがインストールされてる前提になります。
もしまだインストールされていない方は[こちら](https://nodejs.org/ja/download/)からご自身のOSの最新バージンをインストールしてください。
また今回使用するFirebaseはGoogleアカウントが必要なので、もしもない方はアカウントを作成してください。

## 仕様
アプリの仕様は以下の通りです。
- サインアップ、サインインの実装（メールアドレス、パスワード）
- ユーザーごとでにドキュメントを生成

## 使用するもの
- Firebase
    - FireStore
    - FireAuth
- React
    - react-router-dom

## セットアップ
それでは始めていきましょう！！

### Reactのプロジェクトを立ち上げる
Macの場合はターミナル、Windowsの場合はコマンドプロンプトを開いて、お好きなディレクトリに移動してください。移動した後に以下のコマンドを打ちます
```shell
npx create-react-app todolist #任意のフォルダ名で構いません。
```
するとReactのプロジェクトを生成してくれます。（時間がかかります。）

### パッケージのインストール
このプロジェクトで使用するパッケージをインストールしておきます。
```bash
cd todolist #Reactのフォルダへ移動
npm install firebase
npm install react-router-dom
```

### ファイル整理
create-react-appで作成したプロジェクトでいらない部分は削除しておきましょう。以下のファイルを消してください。
- App.css
- App.test.js
- index.css
- logo.svg
- reportWebVitals.js
- setupTests.js
```
src
    ├── App.js
    └── index.js
```
プロジェクトのsrcディレクトリがこうなっていれば成功！！

このまま実行するとエラーが出てしまうので、それぞれのファイルを修正する。
```js:src/App.js
function App() {
  return (
    <div>
      <h1>Hello World</h1>
    </div>
  );
}
export default App;
```
```js:src/index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);
```
## 実装
今回は画面遷移するようにだけ、実装します。機能面の実装は次からなので、まずは入力、画面遷移を実装しましょう。
### ディレクトリとファイルの作成
srcディレクトリの中にcomponentsフォルダを作り以下のようにファイルを配置します。
```
src
    ├── App.js
    ├── components
    │   ├── Home.js
    │   ├── Root.js
    │   ├── SignIn.js
    │   ├── SignUp.js
    │   └── index.js
    ├── context
    │   └── Authcontext.js
    ├── firebase.js
    └── index.js
```
#### App.js
App.jsを少し修正します。
```js:src/App.js
import {Home, SignIn, SignUp, Root} from './components/index'
import { BrowserRouter, Route, Routes } from 'react-router-dom';

function App() {
  return (
      <BrowserRouter>
        <Routes>
            <Route path="/" element={<Root />} />
            <Route path="/signup" element={<SignUp />} />
            <Route path="/signin" element={<SignIn />} />
            <Route path="/home" element={<Home />} />
        </Routes>
      </BrowserRouter>
  );
}

export default App;
```
後ほど記述する、comonentsフォルダのindexファイルから各コンポーネントを、react-router-domから画面遷移のためのモジュールをインポートしてきます。
react-router-domを使えば簡単に画面遷移を行うことができます。

#### index.js
コードを見やすくするために、componentsディレクトリにある全てのモジュールをここから呼び出せるようにします。
```js:src/components/index.js
export {default as Home} from './Home'
export {default as SignIn} from './SignIn'
export {default as SignUp} from './SignUp'
export {default as Root} from './Root'
```

#### Root.js
このアプリの仕様として、ユーザーがログインしているか、していないかによって、表示する画面を変えます。そこで一度Root.jsを経由することで、それを実装します。ここではまだFirebaseと連携していないので、とりあえず、サインイン画面に遷移するように実装します。
```js:src/components/Root.js
import { Navigate } from "react-router-dom"

const Root = () => {
  return (
    <Navigate to="/signin" />
  )
}

export default Root
```

#### SignUp.js(サインアップ画面)
SignUp.jsはサインインするための画面になります。今回の実装ではメールアドレスと、パスワードでアカウントを作るので二つの入力フォームを作成します。作成し終えると、サインインできるようにサインイン画面に移動させます。
```js:src/components/SignUp.js
import { Link, useNavigate } from 'react-router-dom';

const SignUp = () => {
  const navigate = useNavigate();

  const handleSubmit = (event) => {
    const { email, password } = event.currentTarget.elements;
    console.log(email.value, password.value)
    navigate('/signin')
  }

  return (
    <div>
      <h1>Sign Up</h1>
      <form onSubmit={handleSubmit}>
        <div>
          <label>メールアドレス</label>
          <input name="email" type="email" placeholder="email"/>
        </div>
        <div>
          <label>パスワード</label>
          <input name="password" type="password" placeholder="password"/>
        </div>
        <button>登録</button>
      </form>
      <div>
        ログイン済みの場合は<Link to={'/signin'}>こちら</Link>から
      </div>
    </div>
  )
}

export default SignUp;
```
少しだけコードの解説を行います。
`hundleSubmit`関数は`form`タグ内で囲われたボタンをトリガーにして発火します。
この時、inputタグ内のデータを取得することができます。
取得の仕方ですが、いくつかのパターンがあります。
```js:js
const {name, password} = event.currentTarget.elements
//もしくは
const name = event.currentTarget.elements['name']
const password = event.currentTarget.elements['password']
```
どちらでもお好きな方法で構いませんが僕は上の方が好きですね。
ちなみに上の方は変数名を`input`の`name`で指定した値でないといけないのでそこだ要注意です！

#### SignIn.js(サインイン画面)
SignIn.jsではユーザーがサインインできるようにする画面です。SignUp.jsとほとんど同じような内容なので、ここではコードだけを記述します。
```js:SignIn.js
import { useNavigate, Link } from 'react-router-dom'

const SignIn = () => {
  const navigate = useNavigate();
  const handleSubmit = (event) => {
    const { email, password } = event.target.elements;
    console.log(email, password)
    navigate('/home')
  };

  return (
    <div>
      <h1>Sign In</h1>
      <form onSubmit={handleSubmit}>
        <div>
          <label>メールアドレス</label>
          <input name="email" type="email" placeholder="email" />
        </div>
        <div>
          <label>パスワード</label>
          <input name="password" type="password" placeholder="password" />
        </div>
        <div>
          <button>ログイン</button>
        </div>
        <div>
          ユーザ登録は<Link to={'/signup'}>こちら</Link>から
        </div>
      </form>
    </div>
  );
};

export default SignIn;
```

#### Home.js(ホーム画面)
今の所の実装はこれだけで大丈夫です！（後の章で詳しくやります。）
```js:src/components/Home
const Home = () => {
  return (
    <div>
      <h1>Home</h1>
    </div>
  )
}

export default Home
```

### 実行
お疲れ様です。今回の実装では異常になります。試しにプロジェクトを起動させましょう。ターミナル、もしくわcmdで以下のコマンドを打ちます。
```bash:
npm start
```
ローカルサーバーが立ち上がるので、うまく行っていれば、成功です！
画面遷移がうまくいくかもしっかり見ときましょう。

## 次回
今回は画面が遷移するところまで実装しました。次回はFirebaseと連携するところまで実装します！

https://qiita.com/yousuke_1112/items/948021e4f037855e49a0

## 最後に
プログラミング初心者なので、至らないところがあるかも知れません...
もし動かなかったり、全然できなかったり、また、アドバイス等ありましたら気軽にコメントいただけると幸いです！！