Provider: Strange trigger mechanism

Created on 29 May 2019  路  4Comments  路  Source: rrousselGit/provider

I used provider in my project and I fond a strange trigger mechanism.

Widget build(BuildContext context) {
    final notifer = Provider.of<Notifier>(context);
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),

When I push a new page, I noticed that the first page's provider was touched off, but no notifyListeners was called. And when I pop the second page, the first page's provider was touched off again, still no notifyListeners was called. If I removed the
final notifer = Provider.of<Notifier>(context);
then the Widget will not refresh every time I push or pop.

invalid question

Most helpful comment

After a quick test, this is unrelated to provider.
I replaced the Provider.of<Notifier>(context) with a Theme.of(context) and the problem still happens.

Digging a step deeper, I converted MyFirstHomePage into a StatefulWidget to override both deactivate and didChangeDependencies.

It seems that pushing routes calls deactivate on all other routes.
This, in turn, rebuilds _all_ widgets that depend on an InheritedWidget.

Nice catch, but I can't do anything about it. It's an issue on Flutter's end.

All 4 comments

Could you share a minimal reproduction repository?

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

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

class Notifier with ChangeNotifier {}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider<Notifier>(
      builder: (context) => Notifier(),
      child: MaterialApp(
        title: 'Demo',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: MyHomePage(),
      ),
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final notifer = Provider.of<Notifier>(context);
    print("refresh");
    return Scaffold(
      appBar: AppBar(
        title: Text('First Page'),
      ),
      body: Container(),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          Navigator.push(context,
              MaterialPageRoute(builder: (context) => MySecondHomePage()));
        },
        child: Icon(Icons.add),
      ),
    );
  }
}

class MySecondHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("second Page"),
      ),
      body: Container(),
    );
  }
}

For a StatefulWidget, widget will refresh when we do push or pop action. For a StatelessWidget, push or pop action should not make widget refresh. But in this case, an empty provider will make a StatelessWidget refresh every push or pop action.

Indeed. That's intriguing.

At first glance, I don't see any reason behind this.

After a quick test, this is unrelated to provider.
I replaced the Provider.of<Notifier>(context) with a Theme.of(context) and the problem still happens.

Digging a step deeper, I converted MyFirstHomePage into a StatefulWidget to override both deactivate and didChangeDependencies.

It seems that pushing routes calls deactivate on all other routes.
This, in turn, rebuilds _all_ widgets that depend on an InheritedWidget.

Nice catch, but I can't do anything about it. It's an issue on Flutter's end.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

usherwalce picture usherwalce  路  5Comments

wemped picture wemped  路  5Comments

MaxTenco picture MaxTenco  路  5Comments

rrousselGit picture rrousselGit  路  3Comments

stocksp picture stocksp  路  5Comments