Flutter Necestelesswidget和提供商未更新或调用不必要的构建

发布于 2025-02-04 19:06:57 字数 2480 浏览 4 评论 0原文

我正在尝试将提供商无状态窗口小部件页面更新倒计时UI。

在控制台中获得两个打印消息:

当我运行

flutter: build()
flutter: _buildCountDown()

以下所有操作时,我在秒表的每个1秒刻度上都会

如果我:

  • 使页面a statefulwidget
  • consumer< CountdownProvider>语法替换变量访问
return Consumer<CountdownProvider>(
  builder: (_, countdownProvider, __) {
    return Text(countdownProvider.remaining.toString()),
});

但是, UI正确更新,我没有获得build()打印输出,只有_buildCountdown(),这就是我想要的。

q)我做错了什么,这意味着我无法将其作为预期更新的无状态小部件?


  1. main。dart我有这样的提供商:
return MultiProvider(
  providers: [        
    ChangeNotifierProvider(
      create: (_) => CountdownProvider(),
    ),
  ],
)
  1. 我写了一个简单的倒计时提供商-g code- CountDownProvider
class CountdownProvider extends ChangeNotifier {

  int remaining = 0;
  final Stopwatch _stopwatch = Stopwatch();
  late Timer _timer;

  void start(int val) {
    remaining = val;
    _timer = Timer.periodic(const Duration(seconds: 1), _onTick);
    _stopwatch.start();
  }

  void _onTick(Timer timer) {
    remaining--;
    if (remaining < 0) {
      return;
    }
    notifyListeners();
  }

  void stop(bool skipNotify) {
    _timer.cancel();
    _stopwatch.stop();

    if (skipNotify) {
      _stopwatch.reset();
      remaining = 0;
      return;
    }
    notifyListeners();
  }
}
  1. 页面显示它:pagecountdown
class PageCountdown extends StatelessWidget {
  const PageCountdown({
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    // 10 seconds default countdown
    Provider.of<CountdownProvider>(context, listen: false).start(10);

    print("build()");
    return Scaffold(
      body: _buildContent(context),
    );
  }

  Widget _buildContent(BuildContext context) {
    return SafeArea(
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          _buildCountDown(context),
        ],
      ),
    );
  }

  Widget _buildCountDown(BuildContext context) {
    int remaining = Provider.of<CountdownProvider>(context).remaining;

    print("_buildCountDown()");

    return Text(
      remaining.toString(),
    );
  }
}

I'm trying to use Provider with a Stateless widget page to update a countdown UI.

When I run all the below, I get both print messages in the console on each 1 second tick of the stopwatch:

e.g.

flutter: build()
flutter: _buildCountDown()

Also, the remaining value doesn't actually update in the UI.

But if I:

  • make the page a StatefulWidget
  • replace the variable access with Consumer<CountdownProvider> syntax e.g.
return Consumer<CountdownProvider>(
  builder: (_, countdownProvider, __) {
    return Text(countdownProvider.remaining.toString()),
});

...everything works as expected: the UI updates properly and I don't get the build() printout, just the _buildCountDown(), which is what I wanted.

Q) What am I doing wrong that means I can't make this a Stateless widget that updates as expected?


  1. main.dart I have the Provider like so:
return MultiProvider(
  providers: [        
    ChangeNotifierProvider(
      create: (_) => CountdownProvider(),
    ),
  ],
)
  1. I have written a simple countdown provider - CountdownProvider:
class CountdownProvider extends ChangeNotifier {

  int remaining = 0;
  final Stopwatch _stopwatch = Stopwatch();
  late Timer _timer;

  void start(int val) {
    remaining = val;
    _timer = Timer.periodic(const Duration(seconds: 1), _onTick);
    _stopwatch.start();
  }

  void _onTick(Timer timer) {
    remaining--;
    if (remaining < 0) {
      return;
    }
    notifyListeners();
  }

  void stop(bool skipNotify) {
    _timer.cancel();
    _stopwatch.stop();

    if (skipNotify) {
      _stopwatch.reset();
      remaining = 0;
      return;
    }
    notifyListeners();
  }
}
  1. Page to display it: PageCountdown:
class PageCountdown extends StatelessWidget {
  const PageCountdown({
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    // 10 seconds default countdown
    Provider.of<CountdownProvider>(context, listen: false).start(10);

    print("build()");
    return Scaffold(
      body: _buildContent(context),
    );
  }

  Widget _buildContent(BuildContext context) {
    return SafeArea(
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          _buildCountDown(context),
        ],
      ),
    );
  }

  Widget _buildCountDown(BuildContext context) {
    int remaining = Provider.of<CountdownProvider>(context).remaining;

    print("_buildCountDown()");

    return Text(
      remaining.toString(),
    );
  }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

夏日浅笑〃 2025-02-11 19:06:57

PageCountdown是单个小部件,在计数器滴答时会重建。 start(10)构建的开头将重置剩余每个重建。这样的事情将起作用:

class PageCountdown extends StatelessWidget {
  const PageCountdown({
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    // 10 seconds default countdown
    Provider.of<CountdownProvider>(context, listen: false).start(10);

    print("build()");
    return const Scaffold(
      body: Countdown(),
    );
  }
}

class Countdown extends StatelessWidget {
  const Countdown({
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          _buildCountDown(context),
        ],
      ),
    );
  }

  Widget _buildCountDown(BuildContext context) {
    int remaining = Provider.of<CountdownProvider>(context).remaining;

    print("_buildCountDown()");

    return Text(
      remaining.toString(),
    );
  }
}

PageCountdown is the single widget, which is rebuilt when the counter ticks. start(10) in the beginning of build will reset remaining to 10 every rebuild. Something like this will work:

class PageCountdown extends StatelessWidget {
  const PageCountdown({
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    // 10 seconds default countdown
    Provider.of<CountdownProvider>(context, listen: false).start(10);

    print("build()");
    return const Scaffold(
      body: Countdown(),
    );
  }
}

class Countdown extends StatelessWidget {
  const Countdown({
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          _buildCountDown(context),
        ],
      ),
    );
  }

  Widget _buildCountDown(BuildContext context) {
    int remaining = Provider.of<CountdownProvider>(context).remaining;

    print("_buildCountDown()");

    return Text(
      remaining.toString(),
    );
  }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文