Migrate ChangeNotifier from provider to hooks_riverpod

1,581

Quick note - with Provider or Riverpod, you don't really want/need to name the thing you are providing thingProvider. You aren't providing a provider, you're providing a thing if that makes sense.

I did my best to fill in the gaps for the rest of the code you didn't provide, so hopefully, this will help:

class QuestionModel {
  QuestionModel(this.id);

  final int id;
}

class AnswerModel {
  AnswerModel(this.id);

  final int id;
}

class QuestionWithAnswers {
  QuestionWithAnswers(this.question, this.answers);

  final QuestionModel question;
  final List<AnswerModel> answers;
}

class QuestionAnswerNotifier extends ChangeNotifier {
  QuestionAnswerNotifier(this.qwa);

  final QuestionWithAnswers qwa;

  QuestionModel get question => qwa.question;
  List<AnswerModel> get answers => qwa.answers;

  addAnswer(AnswerModel answer) {
    qwa.answers.add(answer);
    notifyListeners();
  }
}

final questionProvider =
    ChangeNotifierProvider.family<QuestionAnswerNotifier, QuestionWithAnswers>(
        (ref, qwa) => QuestionAnswerNotifier(qwa));

class EditQuestionScreen extends HookWidget {
  EditQuestionScreen({
    @required QuestionModel question,
    @required List<AnswerModel> answers,
    Key key,
  })  : qwa = QuestionWithAnswers(question, answers),
        super(key: key);

  final QuestionWithAnswers qwa;

  @override
  Widget build(BuildContext context) {
    final provider = useProvider(questionProvider(qwa));

    // Use data from provider to render your UI, for example:
    return Container(
      child: Column(
        children: <Widget>[
          Text('${provider.question}\n${provider.answers}'),
          RaisedButton(
            onPressed: () => provider.addAnswer(AnswerModel(5)),
            child: Icon(Icons.add),
          )
        ],
      ),
    );
  }
}

There are a few things to note here.

  1. In Riverpod, family is how we pass parameters to providers.
  2. QuestionWithAnswers class bundles the models you want to pass to the provider through the extra parameter provided by family.
  3. The provider's name is suffixed with Provider, rather than the thing it is providing being named as such.
  4. We are providing the ChangeNotifier, so that is what is returned when called useProvider.
Share:
1,581
bcihan
Author by

bcihan

Updated on November 21, 2022

Comments

  • bcihan
    bcihan over 1 year

    I want to move my entire project from provider to riverpod. But I’m stuck at this point.

    class EditQuestionScreen extends StatelessWidget {
      EditQuestionScreen({this.question, this.answers});
    
      final QuestionModel question;
      final List<AnswerModel> answers;
    
      @override
      Widget build(BuildContext context) {
        return ChangeNotifierProvider(
            create: (context) => QuestionProvider(
                question: this.question,
                answers: this.answers),
            child: Container());
      }
    }
    

    This is my provider widget for subwidgets. It's initialized only once. How can I write this class as a HookWidget with riverpod?

  • bcihan
    bcihan over 3 years
    Wow, thanks dude. You created my architecture from zero. We thought the same thing about families. But families did not solve my probem. I would remove this question but others can benefit this answer and notes. Thanks again. Related Issue : github.com/rrousselGit/river_pod/issues/72