Skip to content

useToggle 🔄

はじめに

ブール値の状態管理を簡単に行いたいですか?useToggleはスマートなスイッチのように、truefalseを自由に切り替えることができます!🎛️

モーダルの表示/非表示の制御、テーマモードの切り替え、コンポーネントの展開/折りたたみ状態の管理など、このHookによって状態管理がシンプルかつエレガントになります!

コードデモ

基本的な使い方 🚀

最もシンプルなスイッチ制御から始めましょう:

html
<template>
  <div class="toggle-demo">
    <div class="status-display">
      <span class="status-text">
        現在の状態: {{ isOn ? 'オン 🟢' : 'オフ 🔴' }}
      </span>
    </div>
    
    <div class="control-buttons">
      <button @click="toggle()" class="toggle-btn">
        {{ isOn ? 'オフ' : 'オン' }}
      </button>
      <button @click="toggle(true)" class="force-btn">
        強制オン
      </button>
      <button @click="toggle(false)" class="force-btn">
        強制オフ
      </button>
    </div>
  </div>
</template>
js
import { useToggle } from '@vant/use';

export default {
  setup() {
    // スイッチ状態を作成し、デフォルトはオフ
    const [isOn, toggle] = useToggle();

    // 引数なしの呼び出し:自動的に状態を切り替える
    const handleAutoToggle = () => {
      toggle();
      console.log('状態が切り替わりました:', isOn.value ? 'オン' : 'オフ');
    };

    // 引数ありの呼び出し:特定の状態に設定
    const handleForceOn = () => {
      toggle(true);
      console.log('強制オン!');
    };

    const handleForceOff = () => {
      toggle(false);
      console.log('強制オフ!');
    };

    return {
      isOn,
      toggle,
      handleAutoToggle,
      handleForceOn,
      handleForceOff
    };
  },
};

モーダルコントロール 📱

useToggleを使用してモーダルの状態をエレガントに管理します:

html
<template>
  <div class="modal-demo">
    <!-- トリガーボタン -->
    <button @click="openModal" class="open-btn">
      設定を開く ⚙️
    </button>
    
    <!-- モーダル -->
    <div v-if="isModalVisible" class="modal-overlay" @click="closeModal">
      <div class="modal-content" @click.stop>
        <div class="modal-header">
          <h3>設定パネル</h3>
          <button @click="closeModal" class="close-btn">✕</button>
        </div>
        
        <div class="modal-body">
          <div class="setting-item">
            <label>
              <input 
                type="checkbox" 
                :checked="isDarkMode" 
                @change="toggleDarkMode"
              />
              ダークモード 🌙
            </label>
          </div>
          
          <div class="setting-item">
            <label>
              <input 
                type="checkbox" 
                :checked="isNotificationEnabled" 
                @change="toggleNotification"
              />
              通知プッシュ 🔔
            </label>
          </div>
        </div>
        
        <div class="modal-footer">
          <button @click="resetSettings" class="reset-btn">
            設定をリセット
          </button>
          <button @click="closeModal" class="confirm-btn">
            確認
          </button>
        </div>
      </div>
    </div>
  </div>
</template>
js
import { useToggle } from '@vant/use';
import { watch } from 'vue';

export default {
  setup() {
    // モーダルの表示状態
    const [isModalVisible, toggleModal] = useToggle(false);
    
    // 設定項目の状態
    const [isDarkMode, toggleDarkMode] = useToggle(false);
    const [isNotificationEnabled, toggleNotification] = useToggle(true);
    
    // モーダルを開く
    const openModal = () => {
      toggleModal(true);
      document.body.style.overflow = 'hidden'; // 背景のスクロールを禁止
    };
    
    // モーダルを閉じる
    const closeModal = () => {
      toggleModal(false);
      document.body.style.overflow = ''; // スクロールを復元
    };
    
    // すべての設定をリセット
    const resetSettings = () => {
      toggleDarkMode(false);
      toggleNotification(true);
      console.log('設定がリセットされました!');
    };
    
    // ダークモードの変化を監視
    watch(isDarkMode, (newValue) => {
      document.documentElement.classList.toggle('dark-theme', newValue);
      console.log('ダークモード:', newValue ? 'オン' : 'オフ');
    });
    
    // 通知設定の変化を監視
    watch(isNotificationEnabled, (newValue) => {
      if (newValue) {
        console.log('通知がオンになりました 🔔');
      } else {
        console.log('通知がオフになりました 🔕');
      }
    });
    
    return {
      isModalVisible,
      isDarkMode,
      isNotificationEnabled,
      openModal,
      closeModal,
      toggleDarkMode,
      toggleNotification,
      resetSettings
    };
  }
};

アコーディオンコンポーネント 📋

展開・折りたたみ可能な情報パネルを作成します:

html
<template>
  <div class="accordion-demo">
    <div class="accordion-item" v-for="item in accordionItems" :key="item.id">
      <div 
        class="accordion-header" 
        @click="item.toggle()"
        :class="{ active: item.isExpanded }"
      >
        <h4>{{ item.title }}</h4>
        <span class="accordion-icon">
          {{ item.isExpanded ? '▼' : '▶' }}
        </span>
      </div>
      
      <transition name="accordion">
        <div v-if="item.isExpanded" class="accordion-content">
          <p>{{ item.content }}</p>
        </div>
      </transition>
    </div>
  </div>
</template>
js
import { useToggle } from '@vant/use';
import { reactive } from 'vue';

export default {
  setup() {
    // 複数のアコーディオンアイテムを作成
    const accordionItems = reactive([
      {
        id: 1,
        title: 'Vue 3 とは何ですか?',
        content: 'Vue 3 は漸進的な JavaScript フレームワークで、ユーザーインターフェイスの構築に使用されます。より良いパフォーマンス、より小さなパッケージサイズ、より強力な TypeScript サポートを備えています。',
        ...useToggle(false)
      },
      {
        id: 2,
        title: 'Composition API の利点',
        content: 'Composition API は、より良いロジックの再利用、より明確なコードの組織化、より強力な型推論機能を提供し、大規模プロジェクトのメンテナンスをより容易にします。',
        ...useToggle(false)
      },
      {
        id: 3,
        title: '学習を始めるには?',
        content: '公式ドキュメントから始め、実際のプロジェクトで練習することをお勧めします。基本的な概念から学び、段階的に高度な機能やエコシステムに進んでいくことができます。',
        ...useToggle(false)
      }
    ]);
    
    // すべてのパネルを展開
    const expandAll = () => {
      accordionItems.forEach(item => item.toggle(true));
    };
    
    // すべてのパネルを折りたたむ
    const collapseAll = () => {
      accordionItems.forEach(item => item.toggle(false));
    };
    
    return {
      accordionItems,
      expandAll,
      collapseAll
    };
  }
};

機能スイッチ管理 🎛️

アプリケーションのさまざまな機能を管理する機能スイッチパネルを実装します:

html
<template>
  <div class="feature-toggle-panel">
      <h3>機能スイッチパネル 🎛️</h3>
      
      <div class="feature-grid">
        <div 
          v-for="feature in features" 
          :key="feature.key"
          class="feature-card"
          :class="{ enabled: feature.isEnabled }"
        >
          <div class="feature-header">
            <span class="feature-icon">{{ feature.icon }}</span>
            <h4>{{ feature.name }}</h4>
          </div>
          
          <p class="feature-description">{{ feature.description }}</p>
          
          <div class="feature-controls">
            <label class="toggle-switch">
              <input 
                type="checkbox" 
                :checked="feature.isEnabled"
                @change="feature.toggle()"
              />
              <span class="slider"></span>
            </label>
            <span class="status-text">
              {{ feature.isEnabled ? '有効' : '無効' }}
            </span>
          </div>
        </div>
      </div>
      
      <div class="panel-actions">
        <button @click="enableAllFeatures" class="action-btn primary">
          すべての機能を有効にする
        </button>
        <button @click="disableAllFeatures" class="action-btn secondary">
          すべての機能を無効にする
        </button>
        <button @click="resetToDefaults" class="action-btn">
          デフォルト設定に戻す
        </button>
      </div>
  </div>
</template>
js
import { useToggle } from '@vant/use';
import { reactive, watch } from 'vue';

export default {
  setup() {
    // 機能スイッチのリストを定義
    const features = reactive([
      {
        key: 'notifications',
        name: '通知プッシュ',
        icon: '🔔',
        description: 'アプリ内のメッセージと通知を受け取る',
        defaultValue: true,
        ...useToggle(true)
      },
      {
        key: 'darkMode',
        name: 'ダークモード',
        icon: '🌙',
        description: 'ダークテーマのインターフェイスに切り替える',
        defaultValue: false,
        ...useToggle(false)
      },
      {
        key: 'autoSave',
        name: '自動保存',
        icon: '💾',
        description: 'ユーザーの入力内容を自動的に保存',
        defaultValue: true,
        ...useToggle(true)
      },
      {
        key: 'analytics',
        name: 'データ分析',
        icon: '📊',
        description: '使用データを収集して体験を向上',
        defaultValue: false,
        ...useToggle(false)
      },
      {
        key: 'betaFeatures',
        name: 'ベータ機能',
        icon: '🧪',
        description: '実験的な新機能を有効にする',
        defaultValue: false,
        ...useToggle(false)
      },
      {
        key: 'offlineMode',
        name: 'オフラインモード',
        icon: '📱',
        description: 'ネットワークがない場合でもアプリを使用可能',
        defaultValue: true,
        ...useToggle(true)
      }
    ]);
    
    // すべての機能を有効にする
    const enableAllFeatures = () => {
      features.forEach(feature => feature.toggle(true));
      console.log('すべての機能が有効になりました!');
    };
    
    // すべての機能を無効にする
    const disableAllFeatures = () => {
      features.forEach(feature => feature.toggle(false));
      console.log('すべての機能が無効になりました!');
    };
    
    // デフォルト設定に戻す
    const resetToDefaults = () => {
      features.forEach(feature => {
        feature.toggle(feature.defaultValue);
      });
      console.log('デフォルト設定に戻りました!');
    };
    
    // 機能の状態変化を監視
    features.forEach(feature => {
      watch(() => feature.isEnabled, (newValue) => {
        console.log(`${feature.name} ${newValue ? '有効' : '無効'}`);
        
        // 機能の種類に応じて対応する操作を実行
        switch (feature.key) {
          case 'darkMode':
            document.documentElement.classList.toggle('dark', newValue);
            break;
          case 'notifications':
            if (newValue && 'Notification' in window) {
              Notification.requestPermission();
            }
            break;
          case 'analytics':
            // 分析コードの有効化/無効化
            break;
        }
      });
    });
    
    return {
      features,
      enableAllFeatures,
      disableAllFeatures,
      resetToDefaults
    };
  }
};

ゲーム状態制御 🎮

useToggleを使用してゲームの様々な状態を管理します:

html
<template>
  <div class="game-control-panel">
      <h3>ゲームコントロールパネル 🎮</h3>
      
      <div class="game-status">
        <div class="status-item">
          <span class="label">ゲーム状態:</span>
          <span class="value" :class="{ active: isGameRunning }">
            {{ isGameRunning ? '実行中 ▶️' : '一時停止 ⏸️' }}
          </span>
        </div>
        
        <div class="status-item">
          <span class="label">サウンド:</span>
          <span class="value" :class="{ active: isSoundEnabled }">
            {{ isSoundEnabled ? 'オン 🔊' : 'オフ 🔇' }}
          </span>
        </div>
        
        <div class="status-item">
          <span class="label">デバッグモード:</span>
          <span class="value" :class="{ active: isDebugMode }">
            {{ isDebugMode ? 'オン 🐛' : 'オフ' }}
          </span>
        </div>
      </div>
      
      <div class="game-controls">
        <button 
          @click="toggleGame" 
          class="control-btn"
          :class="{ primary: !isGameRunning, danger: isGameRunning }"
        >
          {{ isGameRunning ? 'ゲームを一時停止' : 'ゲームを開始' }}
        </button>
        
        <button @click="toggleSound" class="control-btn">
          {{ isSoundEnabled ? 'サウンドをオフ' : 'サウンドをオン' }}
        </button>
        
        <button @click="toggleDebug" class="control-btn">
          {{ isDebugMode ? 'デバッグをオフ' : 'デバッグをオン' }}
        </button>
        
        <button @click="resetGame" class="control-btn secondary">
          ゲームをリセット
        </button>
      </div>
      
      <div v-if="isDebugMode" class="debug-panel">
        <h4>デバッグ情報 🔍</h4>
        <pre>{{ debugInfo }}</pre>
      </div>
  </div>
</template>
js
import { useToggle } from '@vant/use';
import { computed, watch } from 'vue';

export default {
  setup() {
    // ゲーム状態管理
    const [isGameRunning, toggleGame] = useToggle(false);
    const [isSoundEnabled, toggleSound] = useToggle(true);
    const [isDebugMode, toggleDebug] = useToggle(false);
    
    // デバッグ情報
    const debugInfo = computed(() => ({
      gameRunning: isGameRunning.value,
      soundEnabled: isSoundEnabled.value,
      debugMode: isDebugMode.value,
      timestamp: new Date().toLocaleTimeString()
    }));
    
    // ゲームをリセット
    const resetGame = () => {
      toggleGame(false);
      toggleSound(true);
      toggleDebug(false);
      console.log('ゲームがリセットされました!');
    };
    
    // ゲーム状態の変化を監視
    watch(isGameRunning, (running) => {
      if (running) {
        console.log('ゲーム開始!🎮');
        // ゲームループを開始
        startGameLoop();
      } else {
        console.log('ゲーム一時停止!⏸️');
        // ゲームループを停止
        stopGameLoop();
      }
    });
    
    // サウンド状態の変化を監視
    watch(isSoundEnabled, (enabled) => {
      if (enabled) {
        console.log('サウンドがオンになりました!🔊');
        // サウンドシステムを有効にする
      } else {
        console.log('サウンドがオフになりました!🔇');
        // サウンドシステムを無効にする
      }
    });
    
    // デバッグモードの変化を監視
    watch(isDebugMode, (debug) => {
      if (debug) {
        console.log('デバッグモードがオンになりました!🐛');
        // デバッグ情報を表示
      } else {
        console.log('デバッグモードがオフになりました!');
        // デバッグ情報を非表示
      }
    });
    
    // ゲームループ制御
    let gameLoopId = null;
    
    const startGameLoop = () => {
      if (gameLoopId) return;
      
      gameLoopId = setInterval(() => {
        // ゲームロジックの更新
        if (isDebugMode.value) {
          console.log('ゲームループ更新...');
        }
      }, 16); // 60 FPS
    };
    
    const stopGameLoop = () => {
      if (gameLoopId) {
        clearInterval(gameLoopId);
        gameLoopId = null;
      }
    };
    
    return {
      isGameRunning,
      isSoundEnabled,
      isDebugMode,
      debugInfo,
      toggleGame,
      toggleSound,
      toggleDebug,
      resetGame
    };
  }
};

API リファレンス 📚

型定義

ts
function useToggle(
  defaultValue?: boolean,
): [Ref<boolean>, (newValue?: boolean) => void];

パラメータ

パラメータ説明デフォルト
defaultValue初期状態の値booleanfalse

戻り値

パラメータ説明
state現在のブール値の状態Ref<boolean>
toggle状態を切り替える関数、具体的な値を渡すかまたは自動的に切り替え(newValue?: boolean) => void

実際の使用シナリオ 🎯

1. インターフェイス制御

  • モーダル管理: ポップアップ、ドロワー、ダイアログの表示/非表示を制御
  • アコーディオン: アコーディオンコンポーネントの展開/折りたたみ状態を管理
  • サイドバー: ナビゲーションバーの表示/非表示を制御

2. 機能スイッチ

  • テーマ切り替え: ダークモードとライトモードの切り替え
  • 機能の有効化: アプリケーション機能のオン/オフ制御
  • 設定管理: ユーザーの環境設定の状態管理

3. ゲーム開発

  • ゲーム状態: 一時停止/再開、サウンドスイッチ、デバッグモード
  • プレイヤー状態: ライフ、スキル状態、装備状態
  • ステージ制御: ステージのロック解除、完了状態

4. フォームインタラクション

  • チェックボックス: 単一オプションの選択状態
  • スイッチボタン: 設定項目の有効/無効
  • 条件表示: 選択に応じて異なる内容を表示

ベストプラクティス 💡

1. 意味的な命名

js
// ✅ 推奨:意味のある変数名を使用
const [isModalVisible, toggleModal] = useToggle(false);
const [isDarkMode, toggleDarkMode] = useToggle(false);

// ❌ 避ける:意味のない変数名の使用
const [flag, setFlag] = useToggle(false);

2. 合理的なデフォルト値の設定

js
// ✅ 推奨:ビジネスニーズに応じて合理的なデフォルト値を設定
const [isNotificationEnabled, toggleNotification] = useToggle(true);  // 通知はデフォルトでオン
const [isDebugMode, toggleDebug] = useToggle(false);  // デバッグモードはデフォルトでオフ

3. 状態変化の監視

js
// ✅ 推奨:状態の変化を監視して副作用を実行
watch(isDarkMode, (newValue) => {
  document.documentElement.classList.toggle('dark', newValue);
  localStorage.setItem('darkMode', String(newValue));
});

4. 組み合わせて使用

js
// ✅ 推奨:複数の関連する状態を組み合わせて管理
const [isLoading, toggleLoading] = useToggle(false);
const [isError, toggleError] = useToggle(false);
const [isSuccess, toggleSuccess] = useToggle(false);

const resetStatus = () => {
  toggleLoading(false);
  toggleError(false);
  toggleSuccess(false);
};

デバッグテクニック 🔧

1. 状態変化ログ

js
// 状態変化のログを追加
const [isVisible, toggleVisible] = useToggle(false);

watch(isVisible, (newValue, oldValue) => {
  console.log(`状態変化: ${oldValue} -> ${newValue}`);
}, { immediate: true });

2. 開発ツールとの統合

js
// 開発環境でデバッグ情報を追加
if (process.env.NODE_ENV === 'development') {
  window.debugToggles = {
    isModalVisible,
    isDarkMode,
    isDebugMode
  };
}

3. 状態の永続化

js
// 状態を localStorage に保存
const [isDarkMode, toggleDarkMode] = useToggle(
  JSON.parse(localStorage.getItem('darkMode') || 'false')
);

watch(isDarkMode, (newValue) => {
  localStorage.setItem('darkMode', JSON.stringify(newValue));
});

パフォーマンス最適化 ⚡

1. 不要な再レンダリングを避ける

js
// ✅ 推奨:computed を使用して派生状態を計算
const statusText = computed(() => 
  isLoading.value ? '読み込み中...' : '読み込み完了'
);

2. 状態のバッチ更新

js
// ✅ 推奨:nextTick を使用してバッチ更新
import { nextTick } from 'vue';

const resetAllStates = async () => {
  toggleLoading(false);
  toggleError(false);
  toggleSuccess(false);
  
  await nextTick();
  console.log('すべての状態がリセットされました');
};

ブラウザ互換性 🌐

useToggle は Vue 3 のリアクティブシステムに基づいており、Vue 3 と互換性のあるすべての環境をサポートします:

  • Chrome 60+
  • Firefox 60+
  • Safari 12+
  • Edge 79+

関連ドキュメント 📖

コアコンセプト

関連する Hooks

実際のアプリケーション

デザインパターン

高度なトピック

Vant に基づく企業向けモバイルソリューション