Flutter changing Text value using RiverPod State management

5.6k views Asked by At

In this below code i made simply code to change Text widget string, default string can be shown into Text widget but when i try to click FloatingActionButton is doesn't change.

clicking on HotReload cause chage it to new value, where i should change to resolve this issue?

import 'package:flutter/material.dart';
import 'package:hooks_riverpod/all.dart';


class MyString extends StateNotifier<String> {
  MyString() : super('Hello World');

  void change(String text) => state = text;
}

final showHello = StateNotifierProvider<MyString>((ref) => MyString());

void main() {
  runApp(ProviderScope(child: MyApp()));
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: Scaffold(
        appBar: AppBar(
          title: Text('SAMPLE'),
        ),
        body: Center(
          child: Consumer(
            builder: (context, watch, _) {
              final s = watch(showHello).state;
              return Text(s);
            },
          ),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () => context.read(showHello).change('Clicked On Button'),
          tooltip: 'Increment',
          child: Icon(Icons.add),
        ), // This trailing comma makes auto-formatting nicer for build methods.
      ),
    );
  }
}
1

There are 1 answers

7
Alex Hartford On BEST ANSWER

April 2021 Update: As of Riverpod >= 0.14.0 the syntax has now been updated (scroll down for original answer). The following demonstrates how the example code provided in the question could be converted to the updated syntax:

import 'package:flutter/material.dart';
// Note importing hooks_riverpod/all.dart is now deprecated
import 'package:hooks_riverpod/hooks_riverpod.dart';


class MyString extends StateNotifier<String> {
  MyString() : super('Hello World');

  void change(String text) => state = text;
}

// Note the extra parameter, String, to specify what is provided by the Notifier
final showHello = StateNotifierProvider<MyString, String>((ref) => MyString());

void main() {
  runApp(ProviderScope(child: MyApp()));
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: Scaffold(
        appBar: AppBar(
          title: Text('SAMPLE'),
        ),
        body: Center(
          child: Consumer(
            builder: (context, watch, _) {
              // Note here, state does not need to be specified.
              final s = watch(showHello);
              return Text(s);
            },
          ),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () {
            // Note that we now specify notifier here to access non-state
            // attributes of the Notifier
            context.read(showHello.notifier).change('Clicked On Button');
          },
          tooltip: 'Increment',
          child: Icon(Icons.add),
        ),
      ),
    );
  }
}

More on upgrading to Riverpod 0.14.0+ can be found here.


The following contains the original answer to the question. It is only valid for riverpod <= 0.13.

Change:

final s = watch(showHello).state;

to:

final s = watch(showHello.state);

The reason for this behavior is that you are watching the notifier itself, not its state. Since the notifier object isn't actually being changed, just the state property, a rebuild is not triggered (which is why you see the update upon hot reload). By watching the state itself, we rebuild whenever the state changes.

This concept extends to other kinds of providers, e.g. listening to the last exposed value of a StreamProvider.

A similar question I answered in the past.