有没有办法在用户停止输入后发送请求?

vox*_*vox 10 search dart flutter

  • 我正在寻找一种在用户停止输入 X 秒后发送 API 请求的方法。
  • 我发送请求的方式是通过 onTextChanged 回调,但是,每次按键都会发送一个请求
  • 我已经看到了在 React 中通过超时来做到这一点的方法,但是,我对颤振相对较新,因此任何帮助将不胜感激

Mah*_*loo 20

您可以使用以下代码来执行此操作:

import 'package:flutter/material.dart';
import 'dart:async';

class Test extends StatefulWidget {
    @override
    State<StatefulWidget> createState() {
        return _TestState();
    }
}

class _TestState extends State<StatefulWidget> {
    Timer searchOnStoppedTyping;

    _onChangeHandler(value ) {
        const duration = Duration(milliseconds:800); // set the duration that you want call search() after that.
        if (searchOnStoppedTyping != null) {
            setState(() => searchOnStoppedTyping.cancel()); // clear timer
        }
        setState(() => searchOnStoppedTyping = new Timer(duration, () => search(value)));
    }

    search(value) {
        print('hello world from search . the value is $value');
    }
    @override
    Widget build(BuildContext context) {
        return TextField(
            onChanged: _onChangeHandler,
            decoration: InputDecoration(
                hintText: 'Search ....'
                ),
            );
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 即使您的代码是这个问题的正确答案,提供一些有关代码的解释也是一个很好的做法。 (2认同)

che*_*ins 5

在 Flutter 中执行此操作的常用方法是使用 RxDart 及其debounce()方法。它允许在启动特定呼叫之前等待一小段时间。

在下面的完整示例中,您会看到它在 1 秒的时间内运行。在该示例中,显示了一条消息,该消息应将调用发送到服务器的位置。

import 'package:flutter/material.dart';
import 'package:rxdart/rxdart.dart';

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      home: new MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final subject = new PublishSubject<String>();

  bool isLoading = false;

  GlobalKey<ScaffoldState> scaffoldKey = new GlobalKey();

  void _textChanged(String text) {
    if (text.isEmpty) {
      setState(() {
        isLoading = false;
      });
      return;
    }
    setState(() {
      isLoading = true;
    });
    scaffoldKey.currentState.showSnackBar(new SnackBar(
      content: new Text("Search for ${text}"),
    ));
  }

  @override
  void initState() {
    super.initState();
    subject.stream.debounce(new Duration(milliseconds: 1000)).listen(_textChanged);
  }

  @override
  void dispose() {
    subject.close();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      key: scaffoldKey,
      appBar: new AppBar(
        title: new Text("Debounce demo"),
      ),
      body: new Container(
        padding: new EdgeInsets.all(8.0),
        child: new Column(
          mainAxisAlignment: MainAxisAlignment.start,
          children: <Widget>[
            new TextField(
              decoration: new InputDecoration(
                hintText: 'Type text to search',
              ),
              onChanged: (string) => (subject.add(string)),
            ),
            isLoading
                ? Padding(
                    padding: const EdgeInsets.all(20.0),
                    child: new CircularProgressIndicator(),
                  )
                : new Container(),
          ],
        ),
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

您可以在以下文章和 Norbert Kozsir编写的代码中看到此代码的实际效果

  • 不完全可以,就像用户在计时器关闭之前改变焦点一样,它会取消计时器并可能保持旧状态。 (2认同)