Escher-js / TaskBucket

0 stars 0 forks source link

Save and recall tasks #5

Open psmuler opened 1 year ago

psmuler commented 1 year ago

データベースとの接続

psmuler commented 1 year ago

オッケーです。次のタスクである、「タスクの作成、保存機能」にいきましょう! 現在はタスク一覧画面しかありませんが、タスクを作成する画面を作るところから始めましょう

psmuler commented 1 year ago

タスク作成画面を実装するために、以下の手順に従ってください。

  1. srcディレクトリ内にcomponentsディレクトリにCreateTask.jsファイルを作成します。

  2. 次に、CreateTask.jsファイルに以下のコードを追加します。これは、タスク作成フォームの簡単な実装です。

import React, { useState } from 'react';

const CreateTask = ({ onSubmit }) => {
  const [name, setName] = useState('');
  const [detail, setDetail] = useState('');
  const [urgency, setUrgency] = useState(1);
  const [importance, setImportance] = useState(1);

  const handleSubmit = (e) => {
    e.preventDefault();
    onSubmit({ name, detail, urgency, importance });
    setName('');
    setDetail('');
    setUrgency(1);
    setImportance(1);
  };

  return (
    <form onSubmit={handleSubmit}>
      <label>
        Name:
        <input type="text" value={name} onChange={(e) => setName(e.target.value)} />
      </label>
      <label>
        Detail:
        <textarea value={detail} onChange={(e) => setDetail(e.target.value)} />
      </label>
      <label>
        Urgency:
        <input type="number" min="1" max="5" value={urgency} onChange={(e) => setUrgency(e.target.value)} />
      </label>
      <label>
        Importance:
        <input type="number" min="1" max="5" value={importance} onChange={(e) => setImportance(e.target.value)} />
      </label>
      <button type="submit">Create Task</button>
    </form>
  );
};

export default CreateTask;
  1. App.jsファイルを編集し、CreateTaskコンポーネントをインポートして表示します。また、タスク作成時に呼び出されるhandleCreateTask関数を定義し、CreateTaskコンポーネントに渡します。
import React, { useState } from 'react';
import TaskTable from './components/TaskTable';
import CreateTask from './components/CreateTask';
import { jsonToTasks } from './utils/jsonToTasks';
import jsonData from './data/tasks.json';
import './App.css';

const initialTasks = jsonToTasks(jsonData);

function App() {
  const [tasks, setTasks] = useState(initialTasks);

  const handleCreateTask = (newTask) => {
    const updatedTasks = [...tasks];
    const i = 5 - newTask.importance;
    const j = newTask.urgency - 1;
    updatedTasks[i][j].push(newTask.name);
    setTasks(updatedTasks);
  };

  return (
    <div className="App">
      <header className="App-header">
        <h1>Task Manager</h1>
      </header>
      <main className="App-main">
        <CreateTask onSubmit={handleCreateTask} />
        <TaskTable tasks={tasks} />
      </main>
    </div>
  );
}

export default App;

これでタスク作成画面が実装されました。新しいタスクを作成してフォームを送信すると、handleCreateTask関数が実行され、tasksステートが更新されます。これにより、TaskTableコンポーネントが再レンダリングされ、新しいタスクが表に追加されます。

タスクの作成と保存機能をさらに強化するには、次のオプションが考えられます。

バリデーション: フォーム内の各フィールドに対して適切なバリデーションルールを適用することで、ユーザーが無効なデータを送信するのを防ぐことができます。例えば、空のタスク名を許可しないようにすることができます。

ローカルストレージの使用: 現在の実装では、ページがリロードされると作成したタスクが消えてしまいます。localStorageを使用してブラウザにタスクデータを保存することで、ページリロード後もタスクデータが保持されます。

データベースへの保存: クライアント側のストレージだけでなく、Firebaseなどのデータベースを使用してタスクデータを永続的に保存することができます。これにより、複数のデバイス間でデータを同期することが可能になります。

以上の機能を実装することで、タスクの作成と保存がより強力で使いやすくなります。それぞれの機能の実装についてご質問があれば、お気軽にお問い合わせください。

psmuler commented 1 year ago
  1. ローカルストレージへの保存から行いましょう。
psmuler commented 1 year ago

ローカルストレージへの保存を実装するには、以下の手順に従ってください。

  1. App.jsファイル内で、useEffectフックをインポートし、tasksステートが更新されるたびにローカルストレージに保存するようにします。
import React, { useState, useEffect } from 'react';
  1. App.js内のAppコンポーネントに、useEffectフックを追加します。これにより、tasksステートが変更されるたびに、localStorageに保存されます。
function App() {
  // ...

  useEffect(() => {
    localStorage.setItem('tasks', JSON.stringify(tasks));
  }, [tasks]);

  // ...
}
  1. また、アプリケーションが初期化される際にローカルストレージからtasksデータを取得するようにuseStateフックを更新します。
const initialTasks = JSON.parse(localStorage.getItem('tasks')) || jsonToTasks(jsonData);

function App() {
  const [tasks, setTasks] = useState(initialTasks);
  // ...
}

これで、アプリケーションがリロードされたときにもtasksデータがローカルストレージから読み込まれ、新しいタスクが正常に保存されます。

注意: localStorageは同期的なAPIであり、大量のデータを読み書きする場合はパフォーマンスに影響がある場合があります。大規模なアプリケーションでは、IndexedDBなどの非同期ストレージAPIや、データベースを検討してください。

psmuler commented 1 year ago

保存ができるようになりました。便利ですね。続いて「3.データベースへの保存: クライアント側のストレージだけでなく、Firebaseなどのデータベースを使用してタスクデータを永続的に保存する」をやりましょう

psmuler commented 1 year ago

Firebase Realtime Databaseを使用してタスクデータを永続的に保存するには、次の手順に従ってください。

  1. Firebase Realtime Databaseをプロジェクトに追加するには、まずFirebaseコンソールにアクセスし、プロジェクトを選択します。次に、「Realtime Database」を選択し、「データベースの作成」をクリックしてデータベースを作成します。

  2. プロジェクトでFirebaseを使用するには、firebaseパッケージをインストールする必要があります。プロジェクトディレクトリで次のコマンドを実行します。

npm install firebase
  1. srcフォルダ内にfirebaseConfig.jsファイルを作成し、Firebaseプロジェクトの設定を追加します。Firebaseコンソールから設定をコピーしてください。
import firebase from 'firebase/app';
import 'firebase/database';

const firebaseConfig = {
  apiKey: "YOUR_API_KEY",
  authDomain: "YOUR_AUTH_DOMAIN",
  databaseURL: "YOUR_DATABASE_URL",
  projectId: "YOUR_PROJECT_ID",
  storageBucket: "YOUR_STORAGE_BUCKET",
  messagingSenderId: "YOUR_MESSAGING_SENDER_ID",
  appId: "YOUR_APP_ID"
};

firebase.initializeApp(firebaseConfig);

export const database = firebase.database();
  1. App.jsファイルでdatabaseをインポートし、タスクデータをFirebase Realtime Databaseに保存する関数を作成します。
import { database } from './firebaseConfig';

// ...

function saveTasksToDatabase(tasks) {
  database.ref('/tasks').set(tasks);
}
  1. useEffectフックを更新して、タスクデータが変更されるたびにデータベースに保存されるようにします。
useEffect(() => {
  localStorage.setItem('tasks', JSON.stringify(tasks));
  saveTasksToDatabase(tasks);
}, [tasks]);
  1. アプリケーションの初期化時に、データベースからタスクデータを読み込む機能を実装します。Appコンポーネント内に以下のuseEffectフックを追加します。
useEffect(() => {
  const fetchTasks = async () => {
    const snapshot = await database.ref('/tasks').once('value');
    const tasksData = snapshot.val();
    if (tasksData) {
      setTasks(tasksData);
    }
  };
  fetchTasks();
}, []);

これで、タスクデータがFirebase Realtime Databaseに保存され、アプリケーションの初期化時にデータベースからデータが読み込まれるようになります。これにより、複数のデバイス間でデータが同期され、リロードしてもデータが失われることはありません。

psmuler commented 1 year ago

firebaseConfig.jsファイルに近いfirebase.jsファイルを以前Hostingするときに作っています。

// Import the functions you need from the SDKs you need
import { initializeApp } from "firebase/app";
import { getAnalytics } from "firebase/analytics";
// TODO: Add SDKs for Firebase products that you want to use
// https://firebase.google.com/docs/web/setup#available-libraries

// Your web app's Firebase configuration
// For Firebase JS SDK v7.20.0 and later, measurementId is optional
const firebaseConfig = {
    apiKey: "AIzaSyC5uc2EW0BPKAZ2bZ9UsCY0u1GUIQsXtQA",
    authDomain: "task-manager-c5803.firebaseapp.com",
    projectId: "task-manager-c5803",
    storageBucket: "task-manager-c5803.appspot.com",
    messagingSenderId: "39297573184",
    appId: "1:39297573184:web:30bcee112b3d19b5a95aa5",
    measurementId: "G-YQVXSPJJNH"
};

// Initialize Firebase
const app = initializeApp(firebaseConfig);
// const analytics = getAnalytics(app);

const db = firebase.firestore();
const auth = firebase.auth();

export { db, auth };

これを書き換えるのでも構いませんか?

psmuler commented 1 year ago

もちろんです。既存のfirebase.jsファイルを変更してRealtime Databaseを追加するには、次の手順に従ってください。

  1. Firebase Realtime DatabaseのSDKをインポートします。
import 'firebase/database';
  1. 既存のfirebaseConfigオブジェクトに、databaseURLプロパティを追加します。この値はFirebaseコンソールのRealtime Databaseセクションから取得できます。
const firebaseConfig = {
  // ...
  databaseURL: "YOUR_DATABASE_URL",
  // ...
};
  1. firebase.jsファイルの最後に、databaseのエクスポートを追加します。
const database = firebase.database();

export { db, auth, database };
  1. App.jsファイルでdatabaseをインポートし、上記で説明したようにタスクデータをFirebase Realtime Databaseに保存する機能を実装します。
import { database } from './firebase';

これで、firebase.jsファイルにRealtime Databaseの設定が追加され、App.jsファイルでその機能を利用できるようになります。

psmuler commented 1 year ago

最後の6.アプリケーションの初期化時に、データベースからタスクデータを読み込む機能を実装します。をもう少し詳しく説明してもらえますか?

psmuler commented 1 year ago

もちろんです。アプリケーションの初期化時に、データベースからタスクデータを読み込む機能を実装するには、App.jsファイルにuseEffectフックを追加します。

useEffectフックは、副作用を実行するためにReactが提供するフックの1つで、コンポーネントのライフサイクルに関連する動作を扱うのに役立ちます。この場合、アプリケーションの初期化時にデータベースからタスクデータを読み込むために使用します。

以下の手順でuseEffectフックを追加して、データベースからタスクデータを読み込む機能を実装します。

  1. App.jsファイルで、useStateおよびuseEffectフックをインポートします。
import React, { useState, useEffect } from 'react';
  1. Appコンポーネント内に、データベースからタスクデータを取得するfetchTasks関数を定義します。この関数では、Firebase Realtime Databaseの/tasksリファレンスからデータを一度だけ取得するためにonce('value')を使用し、結果をsnapshotに格納します。snapshot.val()を使用して取得したデータをtasksDataに格納し、データが存在する場合はsetTasks(tasksData)を実行して、アプリケーションの状態を更新します。
useEffect(() => {
  const fetchTasks = async () => {
    const snapshot = await database.ref('/tasks').once('value');
    const tasksData = snapshot.val();
    if (tasksData) {
      setTasks(tasksData);
    }
  };
  fetchTasks();
}, []);
  1. useEffectフックの第2引数に空の配列[]を指定することで、フックはアプリケーションがマウントされたときに1回だけ実行されるようになります。これにより、アプリケーションの初期化時にデータベースからタスクデータが読み込まれます。

これで、アプリケーションの初期化時にFirebase Realtime Databaseからタスクデータを読み込む機能が実装されました。これにより、ページをリロードしてもタスクデータが保持され、アプリケーションの状態が更新されます。

psmuler commented 1 year ago

App.js内にはuseEffectがすでに宣言されていますが、そこを書き換えるので良いですか?

useEffect(() => {
    localStorage.setItem('tasks', JSON.stringify(tasks));
    saveTasksToDatabase(tasks);
  }, [tasks]);

useEffect(() => {
  const fetchTasks = async () => {
    const snapshot = await database.ref('/tasks').once('value');
    const tasksData = snapshot.val();
    if (tasksData) {
      setTasks(tasksData);
    }
  };
  fetchTasks();
}, []);

に書き換えますか?

psmuler commented 1 year ago

いいえ、既存のuseEffectフックを書き換えるのではなく、新たなuseEffectフックを追加してください。これにより、タスクデータの読み込みと保存がそれぞれ別のuseEffectフックで処理されます。

以下のように、新たなuseEffectフックを追加してデータベースからタスクデータを読み込む機能を実装します。

// 既存の useEffect
useEffect(() => {
  localStorage.setItem('tasks', JSON.stringify(tasks));
  saveTasksToDatabase(tasks);
}, [tasks]);

// 新たに追加する useEffect
useEffect(() => {
  const fetchTasks = async () => {
    const snapshot = await database.ref('/tasks').once('value');
    const tasksData = snapshot.val();
    if (tasksData) {
      setTasks(tasksData);
    }
  };
  fetchTasks();
}, []);

これで、アプリケーションの初期化時にデータベースからタスクデータを読み込む機能が実装されます。また、タスクデータが変更されたときに、ローカルストレージとデータベースへの保存が引き続き行われるようになります。

psmuler commented 1 year ago

ERROR [eslint] src/firebase.js Line 27:12: 'firebase' is not defined no-undef Line 28:14: 'firebase' is not defined no-undef Line 29:18: 'firebase' is not defined no-undef

Search for the keywords to learn more about each error. 現在のfirebase.jsの全体は以下のようになっています。 // Import the functions you need from the SDKs you need import { initializeApp } from "firebase/app"; import { getAnalytics } from "firebase/analytics"; import 'firebase/database';

// TODO: Add SDKs for Firebase products that you want to use // https://firebase.google.com/docs/web/setup#available-libraries

// Your web app's Firebase configuration // For Firebase JS SDK v7.20.0 and later, measurementId is optional const firebaseConfig = { apiKey: "AIzaSyC5uc2EW0BPKAZ2bZ9UsCY0u1GUIQsXtQA", authDomain: "task-manager-c5803.firebaseapp.com", projectId: "task-manager-c5803", storageBucket: "task-manager-c5803.appspot.com", messagingSenderId: "39297573184", appId: "1:39297573184:web:30bcee112b3d19b5a95aa5", measurementId: "G-YQVXSPJJNH", databaseURL: "YOUR_DATABASE_URL"

};

// Initialize Firebase const app = initializeApp(firebaseConfig); // const analytics = getAnalytics(app);

const db = firebase.firestore(); const auth = firebase.auth(); const database = firebase.database();

export { db, auth, database };

psmuler commented 1 year ago

エラーの原因は、firebaseオブジェクトをインポートしていないためです。新しいFirebase SDK v9以降では、モジュールのインポート方法が変更されています。以下のようにコードを修正してください。

import { initializeApp } from "firebase/app";
import { getAnalytics } from "firebase/analytics";
import { getFirestore } from "firebase/firestore";
import { getAuth } from "firebase/auth";
import { getDatabase } from "firebase/database";

// 既存の firebaseConfig はそのまま使用します

// Initialize Firebase
const app = initializeApp(firebaseConfig);
// const analytics = getAnalytics(app);

const db = getFirestore(app);
const auth = getAuth(app);
const database = getDatabase(app);

export { db, auth, database };

これで、firebaseオブジェクトを使用せずに、必要な各機能を個別にインポートし、エラーが解消されるはずです。

psmuler commented 1 year ago

firebase realtime databaseのdatabaseURLはどこから確認できますか

psmuler commented 1 year ago

Firebase Realtime DatabaseのdatabaseURLを確認するには、以下の手順に従ってください。

  1. Firebaseコンソールにアクセスし、対象のプロジェクトを選択します。
  2. 左側のメニューから、「Realtime Database」をクリックします。
  3. 「Realtime Database」ページが表示されます。ページの上部にあるデータベースのURLが、databaseURLです。

このdatabaseURLfirebaseConfigオブジェクトのdatabaseURLプロパティに設定してください。

const firebaseConfig = {
  // ...他の設定
  databaseURL: "https://your-project-id.firebaseio.com", // ここにあなたのデータベースURLを入力してください。
};

これで、Firebase Realtime Databaseとの接続が設定されます。

psmuler commented 1 year ago

データベースでkeyを設定していないかもしれません。

psmuler commented 1 year ago

誤ってchatGPT3.5 turboに変更してしまい履歴が破損、以降受け答えが的を射なくなったので終了。先に「手持ちのデータ全体から必要なデータを読み取って実装役chatGPTに渡してあげる」PM役GPTを実装する必要がある。