kei615ykhm / logic-loom-nextjs14

LogicLoom is a memo app for engineers created as personal developers. There are no release plans. We will proceed with development while learning practical usage of Next.js, TypeScript, TailwindCSS, Vercel, and Supabase.
0 stars 0 forks source link

カスタムhook使用したローカルストレージへの保存が正常に行われない #10

Closed kei615ykhm closed 2 weeks ago

kei615ykhm commented 2 weeks ago

注意

この先、Supabaseのデータベースを使用する際にも同じ原理を使用するものと推測するため、作業ブランチ: experimental/use-local-serverはdevelopにマージされないが、ローカルストレージとカスタムフックの学習の一環で使用する意図があるため削除しない。

作業環境

状態説明

  1. ページリロードすると追加したメモが消える
  2. ブラウザのデベロッパーツールでローカルストレージの動作確認をするも正常動作
  3. ローカルストレージに保存されているように見えたがText content does not match server-rendered HTMLというエラーが発生したため、公式ドキュメントに従って対処
  4. 以下のコードに修正し、console.logを差し込み動作テストを行う
  5. テストの結果、初期化と非同期処理のタイミングとエラーハンドリングのいずれか、またはすべてで誤った処理を行っている可能性があると推測
import { useState, useEffect } from "react";
import { Memo } from "../types";

// メモの状態を管理するカスタムフック
export const useMemos = () => {
  // メモの状態と更新関数を定義
  const [memos, setMemos] = useState<Memo[]>([]);

  // クライアントサイドでのみローカルストレージからメモを取得
  useEffect(() => {
    if (typeof window !== "undefined") {
      console.log("ローカルストレージからメモを取得");
      const storedMemos = localStorage.getItem("memos");
      if (storedMemos) {
        console.log("ローカルストレージで見つかったメモ:", storedMemos);
        setMemos(JSON.parse(storedMemos));
      } else {
        console.log("ローカルストレージにメモはありません");
      }
    }
  }, []);

  // メモの状態が更新されたらローカルストレージに保存
  useEffect(() => {
    if (typeof window !== "undefined") {
      console.log("ローカルストレージにメモを保存");
      localStorage.setItem("memos", JSON.stringify(memos));
    }
  }, [memos]);

  // 新しいメモを追加する関数
  const addMemo = (content: string) => {
    const newMemo: Memo = {
      id: Date.now().toString(), // 現在時刻をIDとして設定
      content,
      createdAt: new Date().toISOString(), // 現在の日時を作成時刻として設定
    };
    console.log("新しいメモを追加:", newMemo);
    setMemos((prevMemos) => [...prevMemos, newMemo]); // 既存のメモに新しいメモを追加
  };

  // 指定したIDのメモを削除する関数
  const deleteMemo = (id: string) => {
    console.log("メモを削除:", id);
    setMemos((prevMemos) => prevMemos.filter((memo) => memo.id !== id)); // 指定したID以外のメモのみを残す
  };

  // メモの状態にアクセスするためのメモ、追加、削除の関数を返す
  return { memos, addMemo, deleteMemo };
};

期待する動作

ローカルストレージに追加したメモが保存され、ページリロード後にも削除されずに永続化していること。

kei615ykhm commented 2 weeks ago

現在のコードのフロー図を作成

誤ったデータフロー

graph TD
    A[コンポーネントマウント] --> B[空の配列でステート初期化]
    B --> C{ローカルストレージにデータあり?}
    C -->|はい| D[ローカルストレージからデータ読み込み]
    C -->|いいえ| E[空の配列のまま]
    D --> F[ステート更新]
    E --> F
    F --> G[ステート変更を検知]
    G --> H[ローカルストレージに保存]
    H --> I[次のレンダリング]
    I --> G
kei615ykhm commented 2 weeks ago

推測内容の掘り下げ

  1. 初期レンダリング時にmemosが空の配列で初期化されてしまい、その状態でローカルストレージに保存されている可能性
  2. useEffectが非同期で動作する際に保存と読み込みのタイミングがズレている可能性
  3. ローカルストレージへのアクセスとJSON.parseでエラーが発生した場合の処理が不足している可能性
kei615ykhm commented 2 weeks ago

この問題は後々のデータベース連携時にも類似する状況が発生する可能性はある。しかし、ローカルストレージ実装に時間をかけるよりも最終目標であるSupabase機能を実装する際、同じ問題が発生した場合に取り組むほうが効率的と考えたためClose: Wontfix 😪とする。