0

I use a cascade of stateful widgets, which are wrapped inside.To prepare WidgetC, I pass along an Object ParamsBundle from WidgetA to WidgetC.

WidgetA 
  -> WidgetB
    -> WidgetC

Inside if WidgetC I use a GestureDetector, to track mouse events. By means of developer.log() I traced, that onPanUpdate callbacks get called.

Within WidgetC's state, I call setState() to change properties of the passed along ParamsBundle. They do get changed. Nevertheless, the visual representation of the app doesn't change.

If I finally resize the browser's window, the visual get's redrawn.

I wonder, if I have to somehow pass some needs_redraw information up from WidgetC, to WidgetB and eventually to WidgetA.

Do I have to? And how to?

I found the solution using ChangeNotifier.

But how to use it? But what would WidgetA do with ChangeNotifier firing?

SteAp
  • 11,853
  • 10
  • 53
  • 88
  • 1
    I think you can study [Stateful and Stateless widget](https://flutter.dev/docs/development/ui/interactive#stateful-and-stateless-widgets) to know how they rebuild (widget only manages its own state). Then you can check the [List of state management](https://flutter.dev/docs/development/data-and-backend/state-mgmt/options). – yellowgray Feb 09 '21 at 01:20

1 Answers1

1

Simplest solution of all is to make the Widget that is supposed to redraw (B or A) a StatefullWidget and then pass some simple function that redraws this widget: () => setState(() {}) down to the widget tree. The most basic way of that is simply as an argument of the child widget and then when the child invokes this function, the parent rebuilds itself.

Of course in some more advanced examples, more efficient solution is to use some state management solution like provider: https://pub.dev/packages/provider, but in simplest examples of all, passing rebuild function down the tree is the right solution.

More complete code:

import 'package:flutter/material.dart';

class WidgetB extends StatefulWidget {
  @override
  _WidgetBState createState() => _WidgetBState();
}

class _WidgetBState extends State<WidgetB> {
  @override
  Widget build(BuildContext context) {
    return WidgetC(redraw: () => setState(() {}));
  }
}

class WidgetC extends StatelessWidget {
  final void Function() redraw;

  const WidgetC({Key key, this.redraw}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: redraw,
    );
  }
}
  • Dependant on the case – Szymon Kowaliński Feb 11 '21 at 22:45
  • It might be. In the simplest solution when widgets are their close relatives (children and a parent or generally close in widget tree) then provider is less efficient. But in some app state data case, its leverage is simple. It does rebuild only widgets that you want and not e.g. the whole app when you transfer data from one small to another small widget that are just far away from each other – Szymon Kowaliński Feb 11 '21 at 22:47
  • When you want to reflect some data changes in UI in some widget that is a **very distant cousin** to the widget causing the change and your only state management solution is passing functions as parameters, then you need to rebuild their **common ancestor**. And in case of distant cousins, widgets' only common ancestor might be e.g. MaterialApp or some other widget that is close to the root of the tree and in that case, you rebuild this widget and also everything beneath it, so possibly the whole app to reflect some small change that is just unluckily placed in the widget tree – Szymon Kowaliński Feb 11 '21 at 22:58
  • But in a lot of cases its perfect approach. Possibly would even work nicely in every case but might be troublesome at some point to pass everything around – Szymon Kowaliński Feb 11 '21 at 23:00