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?

React × Supabase で複数チェックボックスの状態を保存する方法

Posted at

問題

チェックボックスを複数チェックし、supabaseに保存したい。
シンプルですが実装は意外と難しかったです。

解決方法

ソースコードとコメントは以下になります。

import { useEffect, useState } from 'react';
// supabaseの設定ファイルの説明は割愛
import { supabase } from './lib/supabaseClient';

function WordsPage() {
    type Word = {
        word_id: number;
        word_name: string;
        mastered: boolean;
    }

    const [words, setWords] = useState<Word[]>([]);

    useEffect(() => {
        const fetchWords = async () => {
            const { data, error } = await supabase.from('word').select('*')
                .order('updated_at', { ascending: false, nullsFirst: false })
                .order('created_at', { ascending: false });
            if (error) {
                console.error('Error fetching words:', error.message);
            } else {
                setWords(data);
            }
        }
        fetchWords();
    }, []);

    // idを指定する
    const handleCheckboxChange = async (id: number) => {
        // 該当wordのチェックボックスの状態を反転させる
        // updatedWordsは、masteredフラグが反転された新しいwords配列
        const updatedWords = words.map((word) =>
            // 三項演算子 trueの場合はmasteredフラグを反転し、falseの場合はwordをそのまま返す
            word.word_id === id ? { ...word, mastered: !word.mastered } : word
        );

        setWords(updatedWords);
        const { error } = await supabase
            .from('word')
            // 新しい配列 updatedWordsから、word_id が id のオブジェクトを探し、そのオブジェクトの mastered 値を取得
            // ?. は オプショナルチェイニング:見つからなければ undefined を返す
            .update({ mastered: updatedWords.find(word => word.word_id === id)?.mastered })
            // eq は "equal"(等しい) の略で、Supabase(SQLクエリビルダー)で WHERE 条件 を指定する
            .eq('word_id', id)
            .order('updated_at', { ascending: false, nullsFirst: false })
            .order('created_at', { ascending: false });
        if (error) {
            console.error('Error updating word:', error.message);
        }
    }
    return (
        <>
            <h1>Word List</h1>
            {words.map((item) => (
                <div key={item.word_id}>
                    <div>{item.word_name}</div>

                    // チェックボックスの箇所
                    <label>mastered</label>
                    <input
                        type="checkbox"
                        checked={item.mastered}
                        onChange={() => handleCheckboxChange(item.word_id)}
                    />
                </div>
            ))}
        </>
    )
};

export default WordsPage;

実際の画面

チェックボックスにチェックを入れて更新しても、その状態が保存されてチェックが反映されている。
画面収録-2025-05-25-10.36.02.gif

終わりに

チェックボックスの状態を複数管理してデータベースと同期させるのは、一見シンプルですが、
状態管理や非同期処理の扱いが絡むため意外に難しいです。

私が実際にやってみて大事だと感じたのは以下の3点です。

  • やりたいことを明確にする
    → どの単語のチェック状態をどう変えたいのか、仕様をはっきりさせる

  • ChatGPTに何度も相談する
    → 自分でつまずいたポイントや疑問を細かく質問することで理解が深まる

  • 何をやっているかを理解する
    → コードの中で、状態をどう更新し、データベースにどう反映しているかを理解することが肝心

この3つを意識しながら進めると、複雑な機能も着実に実装できるようになります。

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?