🦧

[Flutter] RiverpodのStateProviderの値をdebounceする方法

2022/06/12に公開

Before

例えば、RiverpodのStateProviderを使ったSliderのUIの実装は↓になります。
でも設定途中の値に関心がなくて、設定完了後の値のみ取得したいです。

final sliderProvider = StateProvider<double>((ref) => 0);

class MyHomePage extends ConsumerWidget {
  const MyHomePage({Key? key}) : super(key: key);
  
  Widget build(BuildContext context, WidgetRef ref) {
    StateController<double> sliderState = ref.watch(sliderProvider.notifier);
    final value = ref.watch(sliderProvider);
    return Scaffold(
        appBar: AppBar(
          title: const Text('Flutter Demo Home Page'),
        ),
        body: Column(
          children: [
            const Spacer(),
            Slider(
                value: value, onChanged: (event) => sliderState.state = event),
            Text(value.toString()),
            const Spacer(),
          ],
        ));
  }
}

before

Goal

stateの値をdebounceします。

How

RxDartを使用します。

まずRxDartをimportします。

import 'package:rxdart/rxdart.dart';

Streamを定義します。

final sliderProvider = StateProvider<double>((ref) => 0);

// 1. ConsumerWidget -> ConsumerStatefulWidget
class MyHomePage extends ConsumerStatefulWidget {
  const MyHomePage({Key? key}) : super(key: key);

  
  ConsumerState<ConsumerStatefulWidget> createState() => MyHomePageState();
}

class MyHomePageState extends ConsumerState<MyHomePage> {
  // 2. StreamControllerを定義
  final StreamController<double> _debounceChangesStream = StreamController();

  StreamSubscription? _debounceChangesStreamSubscription;

  String textValue = '';

  
  void initState() {
    super.initState();

    // 4. streamをRxDartのdebounce operatorを使います。
    _debounceChangesStreamSubscription = _debounceChangesStream.stream
        .debounceTime(const Duration(seconds: 1))
        .listen((event) {
      setState(() {
        textValue = event.toString();
      });
    });
  }

  
  Widget build(BuildContext context) {
    StateController<double> sliderState = ref.watch(sliderProvider.notifier);
    final value = ref.watch(sliderProvider);
    // 3. stateの変更をstreamに入れる。
    ref.listen<double>(
        sliderProvider, ((previous, next) => _debounceChangesStream.add(next)));
    return Scaffold(
        appBar: AppBar(
          title: const Text('Flutter Demo Home Page'),
        ),
        body: Column(
          children: [
            const Spacer(),
            Slider(
                value: value, onChanged: (event) => sliderState.state = event),
            Text(textValue),
            const Spacer(),
          ],
        ));
  }

  
  void dispose() {
    _debounceChangesStreamSubscription?.cancel();
    super.dispose();
  }
}

After

after


もしほかに方法もある場合ぜひ教えてください! :]

Discussion