flutter_hooksでList, Set, Mapに対応したuseState関数作ったよ

2025/01/06 21:03公開
2025/01/12 00:38最終更新
Table of Contents
  1. 基本のコード
    1. 使い方

基本のコード

以下のコードは、Set(Listの重複無し版)を書き換えた際にHookStatesetStateメソッドが走るように改造したuseState関数。List、Mapでもこれに倣って作れます。関数名が非常に紛らわしいね

import "dart:collection";

import "package:flutter/widgets.dart";
import "package:flutter_hooks/flutter_hooks.dart";

SetValueNotifier<T> useSetState<T>([Set<T> initialValue = const {}]) {
  return use(_SetStateHook<T>(initialValue: initialValue));
}

class _SetStateHook<T> extends Hook<SetValueNotifier<T>> {
  const _SetStateHook({required this.initialValue});

  final Set<T> initialValue;

  @override
  HookState<SetValueNotifier<T>, Hook<SetValueNotifier<T>>> createState() =>
      _SetStateHookState<T>();
}

class _SetStateHookState<T> extends HookState<SetValueNotifier<T>, _SetStateHook<T>> {
  late final _state = SetValueNotifier<T>(hook.initialValue)
    ..addListener(listener);

  @override
  SetValueNotifier<T> build(BuildContext context) => _state;

  @override
  void dispose() {
    _state.dispose();
  }

  void listener() {
    setState(() {});
  }

  @override
  String get debugLabel => "useSetState<$T>"; // ※使用するCollectionに合わせて変更
}

class SetValueNotifier<T> extends SetBase<T> with ChangeNotifier {
  SetValueNotifier(Set<T> initialValue) : _collection = Set.of(initialValue);

  final Set<T> _collection;

  // Collection操作系のメソッドを網羅的にオーバーライドしてください。
  @override
  bool add(T value) {
    final result = _collection.add(value);
    notifyListeners();
    return result;
  }
  
  @override
  void addAll(Iterable<T> elements) {
    _collection.addAll(elements);
    notifyListeners();
  }

  @override
  bool remove(Object? value) {
    final result = _collection.remove(value);
    notifyListeners();
    return result;
  }
  
  @override
  void removeAll(Iterable<Object?> elements) {
    _collection.removeAll(elements);
    notifyListeners();
  }
  
  @override
  void removeWhere(bool Function(T element) test) {
    _collection.removeWhere(test);
    notifyListeners();
  }

  @override
  bool contains(Object? element) => _collection.contains(element);

  @override
  Iterator<T> get iterator => _collection.iterator;

  @override
  int get length => _collection.length;

  @override
  T? lookup(Object? element) => _collection.lookup(element);

  @override
  Set<T> toSet() => _collection.toSet();
}

使い方

final set = useSetState<int>({});
set.add(1); // .valueは不要
set.add(2);
set.remove(1);
print(set.isNotEmpty); // true