Dropsource / monarch

Monarch is a tool for building Flutter widgets in isolation. It makes it easy to build, test and debug complex UIs.
https://monarchapp.io
MIT License
437 stars 22 forks source link

Is there a way to Preview the ConsumerWidget? #32

Closed yagi2 closed 2 years ago

yagi2 commented 2 years ago

In my project, I am using Riverpod to dynamically change the color in the Widget using StateNotifier, so I have a component that uses ConsumerWidget.

When I try to preview a component that uses a ConsumerWidget, I get the following error

══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
The following StateError was thrown building FooBarView(dirty, state:
_ConsumerState#bbb80):
Bad state: No ProviderScope found

The relevant error-causing widget was:
  FooBarView
  FooBarView:$PROJECT_ROOT_PATH/stories/foobar_stories.dart:415:10

The relevant story is:
  stories/foobar_stories.dart > FooBarView

When the exception was thrown, this was the stack:
#0      ProviderScope.containerOf (package:flutter_riverpod/src/framework.dart:102:7)
#1      ConsumerStatefulElement._container (package:flutter_riverpod/src/consumer.dart:403:53)
#2      ConsumerStatefulElement._container (package:flutter_riverpod/src/consumer.dart)
#3      ConsumerStatefulElement.watch.<anonymous closure> (package:flutter_riverpod/src/consumer.dart:449:14)
#4      _LinkedHashMapMixin.putIfAbsent (dart:collection-patch/compact_hash.dart:453:23)
#5      ConsumerStatefulElement.watch (package:flutter_riverpod/src/consumer.dart:442:26)
#6      FooBarView.build (package:project/foobarview.dart:429:23)
#7      _ConsumerState.build (package:flutter_riverpod/src/consumer.dart:371:19)
#8      StatefulElement.build (package:flutter/src/widgets/framework.dart:4705:27)
#9      ConsumerStatefulElement.build (package:flutter_riverpod/src/consumer.dart:431:20)
#10     HookElement.build (package:flutter_hooks/src/framework.dart:416:27)
#11     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4588:15)
#12     StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4763:11)
#13     Element.rebuild (package:flutter/src/widgets/framework.dart:4311:5)
#14     ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:4566:5)
#15     StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:4754:11)
#16     ComponentElement.mount (package:flutter/src/widgets/framework.dart:4561:5)
...     Normal element mounting (64 frames)
#80     Element.inflateWidget (package:flutter/src/widgets/framework.dart:3631:14)
#81     MultiChildRenderObjectElement.inflateWidget (package:flutter/src/widgets/framework.dart:6261:36)
#82     MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6272:32)
...     Normal element mounting (85 frames)
#167    Element.inflateWidget (package:flutter/src/widgets/framework.dart:3631:14)
#168    Element.updateChild (package:flutter/src/widgets/framework.dart:3380:20)
#169    ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4613:16)
#170    StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4763:11)
#171    Element.rebuild (package:flutter/src/widgets/framework.dart:4311:5)
#172    BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2578:33)
#173    WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:882:21)
#174    RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:363:5)
#175    SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1145:15)
#176    SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1082:9)
#177    SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:996:5)
#181    _invoke (dart:ui/hooks.dart:150:10)
#182    PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:270:5)
#183    _drawFrame (dart:ui/hooks.dart:114:31)
(elided 3 frames from dart:async)

════════════════════════════════════════════════════════════════════════════════════════════════════

Is there any way to avoid the error and preview widget correctly?

fertrig commented 2 years ago

You should be able to use the ProviderScope inside your story. Something like this:

Widget myStory() => ProviderScope(
  overrides: [...],
  child: MyView()
);

You should be able to use the overrides property to pass the color you want to render for each story. Something like this:

Widget red() => ProviderScope(
  overrides: [
    colorProvider.overrideWithValue(MyColors(color: Colors.red))
  ],
  child: MyView()
);

Widget green() => ProviderScope(
  overrides: [
    colorProvider.overrideWithValue(MyColors(color: Colors.green))
  ],
  child: MyView()
);

We have sample stories which use Provider. See provider_screen_stories.dart and provider_navigation_stories.dart. We will add sample stories for riverpod with our next release.

yagi2 commented 2 years ago

Thank you for sharing with me with specific samples. I'm embarrassed why I didn't realize how simple it was.

I will refer to the sample Stories as well. Thank you so much!