デジタル庁デザインシステム:デバウンスとスロットリングの実装ベストプラクティス...

デジタル庁デザインシステム:デバウンスとスロットリングの実装ベストプラクティス

【免费下载链接】design-system-example-components デジタル庁デザインシステムのサンプルコンポーネント 【免费下载链接】design-system-example-components 项目地址: https://gitcode.com/GitHub_Trending/de/design-system-example-components

はじめに:なぜデバウンスとスロットリングが必要なのか?

ユーザーインターフェースのパフォーマンス最適化において、デバウンス(Debounce)とスロットリング(Throttling)は不可欠なテクニックです。デジタル庁デザインシステムのような大規模なデザインシステムでは、これらの技術を適切に実装することで、以下のメリットが得られます:

  • パフォーマンス向上: 不要なレンダリングやAPI呼び出しを削減
  • ユーザー体験の改善: 入力の応答性を維持しながら過剰な処理を防止
  • リソース効率化: サーバー負荷の軽減とバッテリー消費の最適化

デバウンスとスロットリングの基本概念

デバウンス(Debounce)

mermaid

スロットリング(Throttling)

mermaid

デジタル庁デザインシステムにおける実装パターン

カスタムフックによる実装

import { useCallback, useRef } from 'react';

// デバウンスフック
export function useDebounce<T extends (...args: any[]) => void>(
  callback: T,
  delay: number
): T {
  const timeoutRef = useRef<NodeJS.Timeout>();

  return useCallback((...args: Parameters<T>) => {
    if (timeoutRef.current) {
      clearTimeout(timeoutRef.current);
    }
    
    timeoutRef.current = setTimeout(() => {
      callback(...args);
    }, delay);
  }, [callback, delay]) as T;
}

// スロットリングフック
export function useThrottle<T extends (...args: any[]) => void>(
  callback: T,
  delay: number
): T {
  const lastExecutedRef = useRef<number>(0);
  const timeoutRef = useRef<NodeJS.Timeout>();

  return useCallback((...args: Parameters<T>) => {
    const now = Date.now();
    const timeSinceLastExecution = now - lastExecutedRef.current;

    if (timeSinceLastExecution >= delay) {
      lastExecutedRef.current = now;
      callback(...args);
    } else {
      if (timeoutRef.current) {
        clearTimeout(timeoutRef.current);
      }
      
      timeoutRef.current = setTimeout(() => {
        lastExecutedRef.current = Date.now();
        callback(...args);
      }, delay - timeSinceLastExecution);
    }
  }, [callback, delay]) as T;
}

入力コンポーネントでの実装例

import { useState, useCallback } from 'react';
import { Input } from './Input';
import { useDebounce } from '../hooks/useDebounce';

export function SearchInput() {
  const [value, setValue] = useState('');
  const [searchResults, setSearchResults] = useState<string[]>([]);

  // デバウンスされた検索関数
  const debouncedSearch = useDebounce(async (searchTerm: string) => {
    if (searchTerm.length < 2) {
      setSearchResults([]);
      return;
    }
    
    // API呼び出しやフィルタリング処理
    const results = await performSearch(searchTerm);
    setSearchResults(results);
  }, 300);

  const handleInputChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
    const newValue = event.target.value;
    setValue(newValue);
    debouncedSearch(newValue);
  }, [debouncedSearch]);

  return (
    <div>
      <Input
        value={value}
        onChange={handleInputChange}
        placeholder="検索..."
        blockSize="lg"
      />
      {searchResults.length > 0 && (
        <ul className="mt-2 border rounded-8 bg-white">
          {searchResults.map((result, index) => (
            <li key={index} className="px-4 py-2 border-b last:border-b-0">
              {result}
            </li>
          ))}
        </ul>
      )}
    </div>
  );
}

最適な遅延時間の選択基準

ユースケース推奨遅延時間理由
検索入力300-500msユーザーの入力ペースを考慮
ウィンドウリサイズ250msスムーズなレスポンシブ対応
スクロールイベント100ms滑らかなスクロール体験
ドラッグ操作16ms (60fps)アニメーションの滑らかさ

パフォーマンス比較表

手法実行回数メモリ使用量応答性適したユースケース
デバウンス検索、フォーム検証
スロットリングスクロール、リサイズ
未最適化基本的に推奨しない

実装上の注意点とベストプラクティス

1. メモリリークの防止

useEffect(() => {
  return () => {
    // コンポーネントアンマウント時にクリーンアップ
    if (timeoutRef.current) {
      clearTimeout(timeoutRef.current);
    }
  };
}, []);

2. TypeScript型安全性の確保

function useDebounce<T extends (...args: any[]) => void>(
  callback: T,
  delay: number
): (...args: Parameters<T>) => void {
  // 実装...
}

3. テスト容易性の考慮

// テスト用のユーティリティ
export const TEST_UTILS = {
  advanceTimersByTime: (ms: number) => {
    jest.advanceTimersByTime(ms);
  },
  useFakeTimers: () => {
    jest.useFakeTimers();
  },
  useRealTimers: () => {
    jest.useRealTimers();
  }
};

実際のユースケース例

フォーム検証のデバウンス

export function EmailInput() {
  const [email, setEmail] = useState('');
  const [isValid, setIsValid] = useState(true);

  const validateEmail = useDebounce((value: string) => {
    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    setIsValid(emailRegex.test(value));
  }, 500);

  const handleChange = (value: string) => {
    setEmail(value);
    validateEmail(value);
  };

  return (
    <Input
      value={email}
      onChange={(e) => handleChange(e.target.value)}
      isError={!isValid && email.length > 0}
      placeholder="メールアドレス"
    />
  );
}

無限スクロールのスロットリング

export function InfiniteScrollList() {
  const [items, setItems] = useState<string[]>([]);
  const [isLoading, setIsLoading] = useState(false);

  const loadMore = useThrottle(async () => {
    if (isLoading) return;
    
    setIsLoading(true);
    try {
      const newItems = await fetchMoreItems();
      setItems(prev => [...prev, ...newItems]);
    } finally {
      setIsLoading(false);
    }
  }, 1000);

  useEffect(() => {
    const handleScroll = () => {
      const scrollTop = window.scrollY;
      const windowHeight = window.innerHeight;
      const documentHeight = document.documentElement.scrollHeight;
      
      if (scrollTop + windowHeight >= documentHeight - 100) {
        loadMore();
      }
    };

    window.addEventListener('scroll', handleScroll);
    return () => window.removeEventListener('scroll', handleScroll);
  }, [loadMore]);

  return (
    <div>
      {items.map((item, index) => (
        <div key={index} className="p-4 border-b">
          {item}
        </div>
      ))}
      {isLoading && <div className="p-4 text-center">読み込み中...</div>}
    </div>
  );
}

パフォーマンス計測と最適化

// パフォーマンス計測デコレータ
function measurePerformance<T extends (...args: any[]) => any>(
  fn: T,
  label: string
): T {
  return ((...args: Parameters<T>) => {
    const start = performance.now();
    const result = fn(...args);
    const end = performance.now();
    
    console.log(`${label} executed in ${end - start}ms`);
    return result;
  }) as T;
}

// 使用例
const optimizedSearch = measurePerformance(
  useDebounce(searchFunction, 300),
  'Debounced Search'
);

まとめ:デジタル庁デザインシステムでの実装指針

  1. 適切な技術の選択: ユースケースに応じてデバウンスとスロットリングを使い分ける
  2. パフォーマンス計測: 実際のユーザー環境で計測し、最適な遅延時間を決定する
  3. メモリ管理: クリーンアップ処理を確実に実装する
  4. 型安全性: TypeScriptを活用して実行時エラーを防止する
  5. テスト容易性: ユニットテストと統合テストを容易にする設計を心がける

デバウンスとスロットリングを適切に実装することで、デジタル庁デザインシステムのコンポーネントは高いパフォーマンスと優れたユーザー体験を提供できます。これらのテクニックは、大規模なアプリケーションにおいて特に重要であり、システム全体の応答性と効率性に大きく貢献します。

【免费下载链接】design-system-example-components デジタル庁デザインシステムのサンプルコンポーネント 【免费下载链接】design-system-example-components 项目地址: https://gitcode.com/GitHub_Trending/de/design-system-example-components

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值