bcihan
bcihan

Reputation: 317

Migrate ChangeNotifier from provider to hooks_riverpod

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?

Upvotes: 2

Views: 1902

Answers (1)

Alex Hartford
Alex Hartford

Reputation: 6010

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.

Upvotes: 4

Related Questions