15

I have a question about Consumer, of Provider package, in Flutter. I don't understand the purpose of argument "child" in the builder of Consumer

Consumer<MyModel>(builder: (context, myModel, child) {
// doing stuff using myModel variable
});

I could not find any doc about it.

Dimitri Leurs
  • 590
  • 5
  • 19

3 Answers3

27

The child is any widget that doesn't need the data inside of the provider, so when the data gets updated, they don't get re-created since they don't need the data, rather they are passed as a reference to the builder.


    Consumer(
       builder: (context, myModel, child) {
       // child will refer to the MaterialButton provided as the child argument in the 
       // Consumer named parameter,
       // doing stuff using myModel variable
       }
       child: MaterialButton( 
              child: Text("Do some action"), 
              onPressed: () {
              // do some actions
    },),);

Since the MaterialButton doesn't need the state of the provider, but its in the descendant tree, there is no need to re-render that, so it gets passed back to the builder, to save memory and increase performance

Kinman
  • 1,361
  • 9
  • 14
Ahmed Khattab
  • 2,645
  • 2
  • 13
  • 19
  • 3
    But, how this will layout on-screen ? will it be horizontal or vertical or more .... we are returning a widget to the builder and return a widget to the child so how flutter will layout them? – The Chinky Sight May 01 '20 at 10:29
  • its optional , if you need it you display it, else you can omit the child – Ahmed Khattab May 02 '20 at 00:29
  • @ChinkySight i have the same question. I think the answer is that it first tries to use builder widget but if no builder widget is there, then it falls back to child? – MobileMon Nov 23 '20 at 13:43
  • @MobileMon It's not like that, as we know we can use Provider for both dependency injection and state management. If the `Consumer` is of type `ChangeNotifierProvider` and we don't a specific widget to rebuild when `notifyListener()` is called then we can we use the `child` property. – The Chinky Sight Nov 23 '20 at 14:44
  • is this returing the same instance of a Material button from the cache? – Paras Arora Jan 07 '21 at 06:31
6

The child can be used as a part which does not rebuild when the provider value changes and the Consumer rebuilds.

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

final valueProvider = Provider<int>((ref) => 10);
final stateProvider = StateProvider<int>((ref) => 20);

void main() => runApp(ProviderScope(child: const MyApp()));

class MyApp extends StatelessWidget {
  static const title = 'Riverpod Test';
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: title,
      home: MyHomePage(title: title),
    );
  }
}



class MyHomePage extends StatelessWidget {
  final String title;
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(title),
      ),

      body: Center(
        child: Consumer(

          builder: (context, WidgetRef ref, child) {
            print(context);
            final value = ref.watch(valueProvider);
            final stateValue = ref.watch(stateProvider);

            return Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Text('$value, $stateValue'),
                Container(child: child),
                Builder(
                  builder: (context) {
                    print('$context child 2');
                    return Container(child: Text('Child 2'));
                  },
                ),
              ],
            );
          },

          child: Builder(
            builder: (context) {
              print('$context child 1');
              return Text('Child 1');
            },
          ),

        ),
      ),

      floatingActionButton: Consumer(
        builder: (_, WidgetRef ref, __) {
          return FloatingActionButton(
            onPressed: () {
              ref.read(stateProvider.state).state++;
            },
            child: Icon(Icons.add),
          );
        }
      ),
    );
  }
}

The child 2 is inside the Consumer widget and it rebuilds when you press + button. But child 1 never rebuilds

I/flutter (16579): Consumer(dirty, dependencies: [UncontrolledProviderScope], state: _ConsumerState#7620b)
I/flutter (16579): Builder(dirty) child 1
I/flutter (16579): Builder(dirty) child 2
Reloaded 1 of 614 libraries in 1,176ms (compile: 80 ms, reload: 686 ms, reassemble: 299 ms).
I/flutter (16579): Consumer(dirty, dependencies: [UncontrolledProviderScope], state: _ConsumerState#7620b)
I/flutter (16579): Builder(dirty) child 2
I/flutter (16579): Consumer(dirty, dependencies: [UncontrolledProviderScope], state: _ConsumerState#7620b)
I/flutter (16579): Builder(dirty) child 2
I/flutter (16579): Consumer(dirty, dependencies: [UncontrolledProviderScope], state: _ConsumerState#7620b)
I/flutter (16579): Builder(dirty) child 2
Polymath
  • 630
  • 7
  • 11
3

You can pass child widget in consumer. What ever widget you pass as a child will not rebuild when data is changed.

You can avoid unnecessary rebuild of widget using child.

Viren V Varasadiya
  • 25,492
  • 9
  • 45
  • 61
  • 1
    But, how this will layout on-screen ? will it be horizontal or vertical or more .... we are returning a widget to the builder and return a widget to the child so how flutter will layout them? – The Chinky Sight May 01 '20 at 10:33
  • you will get the same behaviour of child widget if you pasted code inside it self. @ChinkySight – Viren V Varasadiya May 01 '20 at 10:36
  • Another question here: I have a widget tree which consists of `Scaffold`, `AppBar`, and a `Column`. The Column has three widgets: `Text`, `Future Builder`, `Flat Button`. I want to rebuild everything(**AppBar, Column ..**) when the state of the provider changes, except the **Future Builder(else it will perform unnecessary read).** – The Chinky Sight May 01 '20 at 10:47
  • 2
    then you must wrap consumer above scaffold and assign future builder to child and use child where ever you want to use in your case between text and flat button. – Viren V Varasadiya May 01 '20 at 11:02
  • Now I got it, how the child works thank you very much :D – The Chinky Sight May 02 '20 at 04:20