背景
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
※この記事は現在執筆中です
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
ついに個人開発を始めることにした。
今回開発するWebアプリはCRUDアプリ。
Webページ上で動作し、ページを閉じてもデータを保持しておくことができる簡単なもの。
その開発の全手順をこの記事にまとめておくことにする。
開発するアプリについて
- CRUDアプリ
- Webページ上で動作する
- ページを閉じてもデータは保持しておくことができる
開発言語/フレームワーク
- フロントエンド:React.js + TypeScript
- バックエンド:Firebase
開発手順
React+TypeScriptアプリの雛形を作成する
- ターミナルにて下記コマンドを実行して、React+TypeScriptアプリの雛形を作成する
npx create-react-app kashikojin1 --template typescript
- ターミナルにて、上記で作成したkashikojin1配下のpackage.josnのあるディレクトリで、下記コマンドを実行して、FirebaseのSDKとルーティング用のパッケージをインストールする
npm install firebase react-router-dom @types/react-router-dom
- React + TypeScriptのアプリを立ち上げてみる
ターミナルにて、package.josnのあるディレクトリで、下記コマンドを実行するとChromeでアプリが起動する
npm run start
Firebaseのプロジェクトを作成する
- Firebaseのアカウントを作成する
- Firebaseのプロジェクトを作成する
- Authenticationメニューから認証機能を有効化する(参考:https://btj0.com/blog/react/firebase-auth/)
- ウェブアプリを追加する(参考:https://btj0.com/blog/react/firebase-auth/)
- Cloud Firestoreにてコレクションとドキュメントを作成する(参考:https://reffect.co.jp/react/react-crud-firebase-9#Cloud_Firestore)
コレクションとドキュメントはこんな感じ
(これはデータベースでいうテーブルとデータ)
React+TypeScript+Firebaseをいろいろ触ってみた(やらなくていい)
1.データ(コレクションの中身の全ドキュメント)を表示する
先程作成したデータ(ドキュメント)を画面に表示してみる
プロジェクトのフォルダ構成を下記のようにする
★マークのファイルはこれから新規作成するファイル
☆マークのファイルはこれから編集するファイル
kashikojin1(プロジェクト名)
└┬ build
┝ node_modules
┝ public
┝ src
| └┬ App.css
| ┝ App.tsx ☆
| ┝ firebase.tsx ★
| ┝ index.css
| ┝ index.js
| └ api
| └ hello.js
┝ .gitignore
┝ package-lock.json
┝ package.json
┝ README.md
┝ tsconfig.json
└ .env ★
では★で示したファイルを作成していこう
REACT_APP_FIREBASE_KEY="Firebaseで作成したウェブアプリのapiKey"
REACT_APP_FIREBASE_DOMAIN="Firebaseで作成したウェブアプリのauthDomain"
REACT_APP_FIREBASE_PROJECT_ID="Firebaseで作成したウェブアプリのprojectId"
REACT_APP_FIREBASE_STORAGE_BUCKET="Firebaseで作成したウェブアプリのstorageBucket"
REACT_APP_FIREBASE_SENDER_ID="Firebaseで作成したウェブアプリのmessagingSenderId"
REACT_APP_FIREBASE_APP_ID="Firebaseで作成したウェブアプリのappId"
REACT_APP_FIREBASE_MEASUREMENT_ID="Firebaseで作成したウェブアプリのmeasurementId"
import { initializeApp } from 'firebase/app';
import { getFirestore } from 'firebase/firestore';
import { getStorage } from 'firebase/storage';
const firebaseConfig = {
apiKey: process.env.REACT_APP_FIREBASE_KEY,
authDomain: process.env.REACT_APP_FIREBASE_DOMAIN,
projectId: process.env.REACT_APP_FIREBASE_PROJECT_ID,
storageBucket: process.env.REACT_APP_FIREBASE_STORAGE_BUCKET,
messagingSenderId: process.env.REACT_APP_FIREBASE_SENDER_ID,
appId: process.env.REACT_APP_FIREBASE_APP_ID,
measurementId: process.env.REACT_APP_FIREBASE_MEASUREMENT_ID,
};
const app = initializeApp(firebaseConfig)
export const db = getFirestore();
export const storage = getStorage();
export default app;
import { db } from '../src/firebase';
import { useState, useEffect } from 'react';
import { collection, getDocs, QuerySnapshot } from 'firebase/firestore';
import './App.css';
type User = {
name: string;
email: string;
age: number;
admin: boolean;
};
function App() {
const [users, setUsers] = useState<User[]>([]);
useEffect(() => {
const usersCollectionRef = collection(db, 'users');
getDocs(usersCollectionRef).then((querySnapshot) => {
const userList: User[] = [];
let count: number = 0;
querySnapshot.docs.map((doc, index) => {
if (count === index ) {
const user: User= {
name: doc.data().name,
email: doc.data().email,
age: doc.data().age,
admin: doc.data().admin,
};
userList.push(user);
count += 1;
};
});
setUsers(userList);
});
}, []);
return (
<div>
{users.map((user, index) => (
<div key={index.toString()}>{user.name}</div>
))}
</div>
);
}
export default App;
ターミナルにて、package.josnのあるディレクトリで、下記コマンドを実行するとChromeでアプリが起動する
npm run start
画面にコレクション1件(ドキュメント2件分)の文字列が出力することを確認できる
2.データ(指定したドキュメント)を表示する
App.tsxの中身を少し変えてみる
import { db } from '../src/firebase';
import { useState, useEffect } from 'react';
import { doc, getDoc } from 'firebase/firestore';
import './App.css';
type User = {
name: string;
email: string;
age: number;
admin: boolean;
};
function App() {
useEffect(() => {
const usersCollectionRef = doc(db, 'users', 'lNQjamODq8TnRoJcvBFC');
getDoc(usersCollectionRef).then((documentSnapshot) => {
if (documentSnapshot.exists()) {
console.log(documentSnapshot.data());
} else {
console.log('No such document!');
}
});
}, []);
return (
<div>
</div>
);
}
export default App;
ターミナルにて、package.josnのあるディレクトリで、下記コマンドを実行するとChromeでアプリが起動する
npm run start
コンソールにドキュメント1件分の内容が出力することを確認できる
3.Cloud Firestoreにてデータ(ドキュメント)を追加したときリアルタイムでデータを出力する
App.tsxの中身を少し変えてみる
import { db } from '../src/firebase';
import { useEffect } from 'react';
import { collection, onSnapshot } from 'firebase/firestore';
import './App.css';
type User = {
name: string;
email: string;
age: number;
admin: boolean;
};
function App() {
useEffect(() => {
const usersCollectionRef = collection(db, 'users');
const unsub = onSnapshot(usersCollectionRef, (querySnapshot) => {
querySnapshot.docs.map((doc) => {
console.log(doc.data());
});
});
return unsub;
}, []);
return (
<div>
</div>
);
}
export default App;
ターミナルにて、package.josnのあるディレクトリで、下記コマンドを実行するとChromeでアプリが起動する
npm run start
Cloud Firestoreにてデータ(ドキュメント)を追加すると、ドキュメントがコンソールに出力することを確認できる
4.React+TypeScriptアプリの画面上からデータを追加する
App.tsxの中身を少し変えてみる
import { useState,useEffect } from 'react';
import { db } from '../src/firebase';
import { addDoc, collection, onSnapshot } from 'firebase/firestore';
import { useForm, SubmitHandler } from 'react-hook-form';
import './App.css';
type User = {
name: string;
email: string;
age: number;
admin: boolean;
};
function App() {
const [users, setUsers] = useState<User[]>([]);
const { register,
handleSubmit,
watch,
formState: { errors }
} = useForm<User>();
const onSubmit: SubmitHandler<User> = (data) => {
console.log('onSubmit', data);
const usersCollectionRef = collection(db, 'users');
const documentRef = addDoc(usersCollectionRef, {
name: data.name,
email: data.email,
age: data.age,
admin: false,
});
console.log(documentRef);
};
useEffect(() => {
let userList: User[] = [];
const usersCollectionRef = collection(db, 'users');
const unsub = onSnapshot(usersCollectionRef, (querySnapshot) => {
querySnapshot.docs.map((doc) => {
const user: User= {
name: doc.data().name,
email: doc.data().email,
age: doc.data().age,
admin: doc.data().admin,
};
userList.push(user);
});
setUsers(userList);
});
return unsub;
});
return (
<div>
<form onSubmit={handleSubmit(onSubmit)}>
<div>
<label>名前</label>
<input defaultValue="test" {...register('name')} />
</div>
<div>
<label>年齢</label>
<input defaultValue="test" {...register('age')} />
</div>
<div>
<label>メールアドレス</label>
<input defaultValue="test" {...register('email')} />
</div>
{errors.name && (
<span>Error!!!</span>
)}
<input value="登録" type="submit" />
</form>
<div>
{users.map((user, index) => (
<div key={index.toString()}>{user.name}</div>
))}
</div>
</div>
);
}
export default App;
ターミナルにて、package.josnのあるディレクトリで、下記コマンドを実行するとChromでアプリが起動する
npm run start
入力フォームに文字列を入力して登録ボタンを押下すると、Cloud FIrestoreへデータが登録され、登録されているデータが画面に出力されることを確認できる
5.React+TypeScriptアプリの画面上からデータを削除する
App.tsxの中身を少し変えてみる
import { useState,useEffect } from 'react';
import { db } from '../src/firebase';
import { addDoc, collection, onSnapshot } from 'firebase/firestore';
import { useForm, SubmitHandler } from 'react-hook-form';
import './App.css';
type User = {
name: string;
email: string;
age: number;
admin: boolean;
};
function App() {
const [users, setUsers] = useState<User[]>([]);
const { register,
handleSubmit,
watch,
formState: { errors }
} = useForm<User>();
const onSubmit: SubmitHandler<User> = (data) => {
console.log('onSubmit', data);
const usersCollectionRef = collection(db, 'users');
const documentRef = addDoc(usersCollectionRef, {
name: data.name,
email: data.email,
age: data.age,
admin: false,
});
console.log(documentRef);
};
useEffect(() => {
let userList: User[] = [];
const usersCollectionRef = collection(db, 'users');
const unsub = onSnapshot(usersCollectionRef, (querySnapshot) => {
querySnapshot.docs.map((doc) => {
const user: User= {
name: doc.data().name,
email: doc.data().email,
age: doc.data().age,
admin: doc.data().admin,
};
userList.push(user);
});
setUsers(userList);
});
return unsub;
});
return (
<div>
<form onSubmit={handleSubmit(onSubmit)}>
<div>
<label>名前</label>
<input defaultValue="test" {...register('name')} />
</div>
<div>
<label>年齢</label>
<input defaultValue="test" {...register('age')} />
</div>
<div>
<label>メールアドレス</label>
<input defaultValue="test" {...register('email')} />
</div>
{errors.name && (
<span>Error!!!</span>
)}
<input value="登録" type="submit" />
</form>
<div>
{users.map((user, index) => (
<div key={index.toString()}>{user.name}</div>
))}
</div>
</div>
);
}
export default App;
ターミナルにて、package.josnのあるディレクトリで、下記コマンドを実行するとChromでアプリが起動する
npm run start
一覧の右側にある削除ボタンを押下すると、ドキュメントIDをキーにCloud FIrestoreからデータを削除する