简体   繁体   中英

Flutter - FutureBuilder in SearchDelegate with Delay Request

I was struggling implement simple search function using SearchDelegate . I want to wait 2 second after user stop typing and then make a call request to an API.

I already check this question: How to debounce search suggestions in flutter's SearchPage Widget? and use this package https://pub.dev/packages/debounce_throttle but still not working as I expected. Every time user typing a new character, the app immediately make a call request.

This is sample code for buildResults function

@override
Widget buildResults(BuildContext context) {
  return FutureBuilder(
    builder: (BuildContext context, AsyncSnapshot<List<Place>> snapshot) {
      if (snapshot.connectionState == ConnectionState.done) {
        return ListView.builder(
          itemBuilder: (context, index) => ListTile(
            leading: Icon(Icons.location_city),
            title: Text(snapshot.data![index].name),
            onTap: () { ... do something ... },
          ),
          itemCount: snapshot.data!.length,
        );
      } else {
        return Center(child: CircularProgressIndicator());
      }
    },
    future: queryChanged(query),
  );
}

and Future function to make a call request

Future<List<Place>> _getLocation() async {
  List<Place> displayPlaces = [];
  ...
  ...
  return displayPlaces;
}

Debouncer code

final debouncer = Debouncer<String>(Duration(milliseconds: 2000), initialValue: '');
Future<List<Place>> queryChanged(String query) async {
  debouncer.value = query;
  return _getLocation();
}

This code works for me:

import 'package:debounce_throttle/debounce_throttle.dart';
import 'dart:async';

class AddressSearch extends SearchDelegate<Suggestion?> {
  
  Completer<List<Suggestion>> _completer = Completer();

  late final Debouncer _debouncer = Debouncer(Duration(milliseconds: 300),
    initialValue: '',
    onChanged: (value) {
      _completer.complete(_fetchSuggestions(value)); // call the API endpoint
    }
  );

  @override
  Widget buildSuggestions(BuildContext context) {
   
    _debouncer.value = query; // update the _debouncer
    _completer = Completer(); // re-create the _completer, 'cause old one might be completed already 

    return FutureBuilder<List<Suggestion>>(
        future: _completer.future,
        builder: (context, snapshot) {

   /* render your suggestions here */
          if (snapshot.connectionState == ConnectionState.done) {
              // If we got an error
              if (snapshot.hasError) {
                return Center(
                  child: Text(
                    '${snapshot.error} occured',
                    style: TextStyle(fontSize: 18),
                  ),
                );

                // if we got our data
              } else if (snapshot.hasData) {
                // Extracting data from snapshot object

                return ListView.builder(
                  itemBuilder: (context, index) => ListTile(
                    title: Text((snapshot.data?[index])!.label), // or whatever field you have in your Suggestion class
                    onTap: () {
                      close(context, snapshot.data?[index]);
                    },
                  ),
                  itemCount: snapshot.data?.length,
                );
              }
            }

            // Displaying LoadingSpinner to indicate waiting state
            return Center(
              child: CircularProgressIndicator(),
            );
          }
    );
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM