Search code examples
flutterflutter-provider

Selector in Provider of Flutter not working


I using provider 4.0.3

My pseudocode code is

class MyModel with ChangeNotifier
User user //{nickname: 'john', age: 1}
//...



ChangeNotifierProvider<MyModel>
(create : (_)=>MyModel()
child: //MyModel model = Provider.of(context);
scafold
 body: Column(
   [
      Selector<MyModel, String>(
        selector : (_, m) => m.user.nickname,
        builder : (_,nickname,___) => Text(nickname)
      )
      RaisedButton(onPressed:() => model.user.nickname = 'none' )
   ]
)
//...

I expected

'RaisedButton preesed -> change nickname.'

but It not working..

What i missed?


Solution

  • You can copy paste run full code below

    code snippet

    class ItemWidget extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Selector<MyModelProvider, User>(
          builder: (context, user, child) {
            print("item widget rebuild");
            return Text('${user.nickName}');
          },
          shouldRebuild: (User pre, User next) {
            print("pre: ${pre.nickName} next: ${next.nickName}");
            print(pre != next);
            return pre != next;
          },
          selector: (buildContext, modelProvider) => modelProvider.user,
        );
      }
    }
    
    class User extends Equatable {
      ...
      User copyWith({String nickName, int age}) => User(
            nickName: nickName ?? this.nickName,
            age: age ?? this.age,
          );
    
      @override
      List<Object> get props => [nickName, age];
    }
    
    class MyModelProvider extends ChangeNotifier {
      User user = User(nickName: "john", age: 1);
    
      setUserNickName(String newNickName) {
        user = user.copyWith(
            nickName:
                newNickName); //select relies on the value obtained to be immutable
        print(user.nickName);
        notifyListeners();
      }
    }
    

    working demo

    enter image description here

    full code

    import 'package:flutter/material.dart';
    import 'package:flutter/foundation.dart';
    import 'package:provider/provider.dart';
    import 'package:equatable/equatable.dart';
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MultiProvider(
          providers: [
            ChangeNotifierProvider(
              create: (BuildContext context) => MyModelProvider(),
            ),
          ],
          child: MaterialApp(
              title: 'Flutter Demo',
              theme: ThemeData(
                primarySwatch: Colors.teal,
              ),
              home: MyHomePage()),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      @override
      Widget build(BuildContext context) {
        return SafeArea(
          child: Scaffold(
            body: Center(
                child: Column(
              children: <Widget>[
                ItemWidget(),
              ],
            )),
            floatingActionButton: FloatingActionButton(
              onPressed: () {
                Provider.of<MyModelProvider>(context, listen: false)
                    .setUserNickName("this is new name");
              },
            ),
          ),
        );
      }
    }
    
    class ItemWidget extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Selector<MyModelProvider, User>(
          builder: (context, user, child) {
            print("item widget rebuild");
            return Text('${user.nickName}');
          },
          shouldRebuild: (User pre, User next) {
            print("pre: ${pre.nickName} next: ${next.nickName}");
            print(pre != next);
            return pre != next;
          },
          selector: (buildContext, modelProvider) => modelProvider.user,
        );
      }
    }
    
    class User extends Equatable {
      String nickName;
      int age;
    
      User({this.nickName, this.age});
      User copyWith({String nickName, int age}) => User(
            nickName: nickName ?? this.nickName,
            age: age ?? this.age,
          );
    
      @override
      List<Object> get props => [nickName, age];
    }
    
    class MyModelProvider extends ChangeNotifier {
      User user = User(nickName: "john", age: 1);
    
      setUserNickName(String newNickName) {
        user = user.copyWith(
            nickName:
                newNickName); //select relies on the value obtained to be immutable
        print(user.nickName);
        notifyListeners();
      }
    }
    

    output

    I/flutter ( 7707): item widget rebuild
    I/flutter ( 7707): this is new name
    I/flutter ( 7707): pre: john next: this is new name
    I/flutter ( 7707): true
    I/flutter ( 7707): item widget rebuild
    I/flutter ( 7707): this is new name
    I/flutter ( 7707): pre: this is new name next: this is new name
    I/flutter ( 7707): false
    I/flutter ( 7707): this is new name
    I/flutter ( 7707): pre: this is new name next: this is new name
    I/flutter ( 7707): false