hieuph13
hieuph13

Reputation: 33

Flutter Riverpod StateProvider having slow rebuild of widget when using watch

I'm using Riverpod with StateProvider for my app.

The home page will change based on tabs clicked. When i click the ListTile tab to trigger the ref.read, it rebuild super fast: But when i click the leading IconButton in Appbar which trigger ref.read(countProvider.notifier).state = 0; it takes me fews seconds to reload the back to 0. How do i fix this? Full code: layout.dart:

Set<Widget> _pages = {
  const HomeUI(),
  const FAQ(),
  const Setting(),
};

class Layout extends ConsumerStatefulWidget {
  const Layout({super.key});

  @override
  LayoutState createState() => LayoutState();
}

class LayoutState extends ConsumerState<Layout> {

  bool isHome = true;

  @override
  Widget build(BuildContext context) {
    final tab = ref.watch(countProvider);
    if (tab != 0) {
      isHome = false;
    } else {
      isHome = true;
    }
    return Scaffold(
      drawer: const Sidebar(),
      appBar: isHome
          ? AppBar(
              leading: Builder(builder: (context) {
                return IconButton(
                  icon: const Icon(FontAwesomeIcons.bars),
                  color: CustomColors.mainText,
                  onPressed: () {
                    Scaffold.of(context).openDrawer();
                  },
                );
              }),
              actions: [
                Padding(
                  padding: const EdgeInsets.only(right: 20),
                  child: IconButton(
                    icon: const Icon(FontAwesomeIcons.magnifyingGlass),
                    color: CustomColors.mainText,
                    onPressed: () {},
                  ),
                ),
              ],
              backgroundColor: Colors.transparent,
            )
          : null,
      backgroundColor: CustomColors.background,
      body: Stack(children: <Widget>[
        _pages.elementAt(tab),
        const MiniPlayer(),
      ]),
    );
  }
}

faq_screen.dart

class FAQ extends StatelessWidget {
  const FAQ({super.key});

  @override
  Widget build(BuildContext context) {
    return Consumer(
      builder: (context, ref, child) {
        return Scaffold(
          appBar: AppBar(
            leading: IconButton(
              icon: const Icon(Icons.arrow_back),
              onPressed: () {
                ref.read(countProvider.notifier).state = 0;
              },
            ),
            title: const Text('FAQ'),
          ),
          body: const Center(
            child: Text('FAQ'),
          ),
        );
      },
    );
  }
}

sidebar.dart

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';

import '../utilities/color.dart';
import '../utilities/provider.dart';

class Sidebar extends StatelessWidget {
  const Sidebar({super.key});

  @override
  Widget build(BuildContext context) {
    return Drawer(
      backgroundColor: CustomColors.background,
      child: Consumer(
        builder: (context, ref, child) => ListView(
          padding: EdgeInsets.zero,
          children: <Widget>[
            UserAccountsDrawerHeader(
              accountName: const Text("Wolhaiksong",
                  style: TextStyle(
                      color: Colors.white,
                      fontFamily: 'Gilroy',
                      fontWeight: CustomColors.semiBold)),
              accountEmail: const Text("[email protected]",
                  style: TextStyle(
                      color: Colors.white,
                      fontFamily: 'Gilroy',
                      fontWeight: CustomColors.regular)),
              currentAccountPicture: CircleAvatar(
                child: ClipOval(
                  child: Image.asset('assets/user.jpg'),
                ),
              ),
              decoration: const BoxDecoration(
                image: DecorationImage(
                    image: AssetImage('assets/wallpaper.jpg'),
                    fit: BoxFit.cover),
              ),
            ),
            ListTile(
              leading: const Icon(
                FontAwesomeIcons.lightbulb,
                color: CustomColors.gray,
              ),
              title: const Padding(
                padding: EdgeInsets.all(15.0),
                child: Text('FAQs',
                    style: TextStyle(
                      color: CustomColors.mainText,
                      fontWeight: CustomColors.semiBold,
                      fontFamily: 'Gilroy',
                    )),
              ),
              onTap: () {
                ref.read(countProvider.notifier).state = 1;
                Navigator.pop(context);
              },
            ),
            ListTile(
              leading: const Icon(
                FontAwesomeIcons.gear,
                color: CustomColors.gray,
              ),
              title: const Padding(
                padding: EdgeInsets.all(15.0),
                child: Text('Settings',
                    style: TextStyle(
                      color: CustomColors.mainText,
                      fontWeight: CustomColors.semiBold,
                      fontFamily: 'Gilroy',
                    )),
              ),
              onTap: () {
                ref.read(countProvider.notifier).state = 2;
                Navigator.pop(context);
              },
            ),
          ],
        ),
      ),
    );
  }
}

provider.dart

final countProvider = StateProvider<int>((ref) {
  return 0;
});

Upvotes: 3

Views: 231

Answers (2)

hieuph13
hieuph13

Reputation: 33

I'm sorry guys, turns out the problem is not Riverpod but the async function i used to extract dominant color from the image.

static Future<Color> generatePaletteColor(url) async {
    final PaletteGenerator paletteGenerator =
        await PaletteGenerator.fromImageProvider(
        AssetImage(url),
    );
    return paletteGenerator.paletteColors[0].color;
}

And I use it in initState so it runs everytime countProvider change

@override
void initState() {
    super.initState();
    CustomColors.generatePaletteColor(widget.song.artWork).then((value) {
        if (mounted) {
            setState(() {
                glowColor = value;
            });
        }
    });
}

Is there anyway to move the async function outside of this or prevent initState from rerun everytime rebuilt?

Upvotes: 0

Ruble
Ruble

Reputation: 4844

Since you basically want to reset your provider to 0, instead of setting the value directly, you can try this:

ref.refresh(countProvider);

Upvotes: 0

Related Questions