1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Supabaseの戻り値でクラスメソッドが呼べない (is not a function) 問題を解決する方法

Posted at

はじめに

Supabaseとクラスを組み合わせた処理で

Uncaught TypeError: result.getFormattedDate is not a function

というエラーに遭遇しました。解決までに時間がかかったので、同じエラーで困っている方の参考になればと思い記事にまとめます。

エラーが発生時のソースコード

sample.tsx
import { useEffect, useState } from "react";
import { SearchHistory } from "../domain/SearchHistory";
import { fetchUserSearchHistory } from "../service/fetchUserSearchHistory";

export const SubstituteSearch = () => {
    const [searchResults, setSearchResults] = useState<SearchHistory[]>([]);

    //ユーザーごとの検索履歴を表示する
    const userSearchHistory = async () => {
        // ユーザーの検索履歴を取得して表示する処理
        const userSearchHistory = await fetchUserSearchHistory();
        setSearchResults(userSearchHistory);
    };

    useEffect(() => {
        userSearchHistory();
    }, []);

    return (
        <>
            <table>
                <thead>
                    <tr>
                        <th>No</th>
                        <th>代替したいもの</th>
                        <th>出力結果</th>
                        <th>出力した日付</th>
                    </tr>
                </thead>
                <tbody>
                    {searchResults.map((result, index) => (
                        <tr key={result.id}>
                            <td>{index + 1}</td>
                            <td>{result.query}</td>
                            <td>{result.ai_response}</td>
                             {/* Supabaseが返すのはただのオブジェクト(クラスのインスタンスではない)*/}
                            <td>{result.getFormattedDate()}</td>
                        </tr>
                    ))}
                </tbody>
            </table>
        </>
    );
};

SearchHistory.tsx
export class SearchHistory {
  constructor(
    public id: number,
    public user_id: number,
    public query: string,
    public ai_response: string,
    public created_at: string
  ) {}

  getFormattedDate(): string {
    const date = new Date(this.created_at);
    const yyyy = date.getFullYear();
    const mm = String(date.getMonth() + 1).padStart(2, "0");
    const dd = String(date.getDate()).padStart(2, "0");

    return `${yyyy}/${mm}/${dd}`;
  }
}

fetchUserSearchHistory.tsx
//ユーザーごとの検索履歴を取得する関数
export const fetchUserSearchHistory = async () => {
  const response = await supabase
    .from("search_history")
    .select("*")
    .eq("user_id", 1) 
    .limit(5)

  if (response.error) {
    console.error("Error fetching user search history:", response.error);
    return [];
  }
  console.log("fetchUserSearchHistory response:", response);
  return response.data;
};

原因

Supabaseが返すのはただのJSONオブジェクト配列で、SearchHistoryクラスのインスタンスではなかった。
つまり 型が SearchHistory であってもメソッドは使えないため、getFormattedDate()が存在せずエラーになっていました。

解決法

解決の方針はSupabaseから返ったオブジェクトを SearchHistory クラスに変換することでした。
上記のコードのfetchUserSearchHistory.tsにSupabase から取ったオブジェクトを SearchHistory クラスに変換する機能を追加しました。

fetchUserSearchHistory.tsx
import { SearchHistory } from "../domain/SearchHistory";
import { SearchHistoryRow } from "../domain/SearchHistoryRow";
import { supabase } from "../utils/supabase";

//ユーザーごとの検索履歴を取得する関数
export const fetchUserSearchHistory = async () => {
  const response = await supabase
    .from("search_history")
    .select("*")
    .eq("user_id", 1) // 例としてuser_idが1のユーザーの履歴を取得
    .limit(5);
  if (response.error) {
    console.error("Error fetching user search history:", response.error);
    return [];
  }
+  //Supabase から取ったオブジェクトを SearchHistory クラスに変換
+  const histories = (response.data || []).map(
+    (history: SearchHistoryRow) =>
+      new SearchHistory(
+        history.id,
+        history.user_id,
+        history.query,
+        history.ai_response,
+        history.created_at
+      )
  );
-  console.log("fetchUserSearchHistory response:", response);
+  console.log("fetchUserSearchHistory response:", histories);
-  return response.data;
+  return histories;
};
SearchHistoryRow.ts
export type SearchHistoryRow = {
  id: number;
  user_id: number;
  query: string;
  ai_response: string;
  created_at: string;
};

終わりに

今回わかったのは、Supabaseの戻り値は「ただのデータ(プレーンなオブジェクト)」であり、
そのままではクラスのメソッドを利用できないということでした。

もしドメインクラス(今回の SearchHistory)のメソッドを呼びたい場合は、
必ず new SearchHistory(...)のようにして 自分でインスタンス化する処理を挟む必要があることを理解しました。

参考

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?