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 1: chunhunghan

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


Solution 2: Ganesh Shirole

There is no meaning of Selector in this answer, Whole tree rebuilds if we use

final modelProvider = Provider.of<ModelProvider>(context, listen: true);

The right answer is Selector will not work if you change properties of the object.