I've started to learning about Flutter's inherited widgets and i have a question.
Why do we need an InheritedWidget if we can get data from context.findAncestorOfExactType?
And that updateShouldNotify... Like, it notifies child widgets when some condition is true, and they are anyway running their build methods after InheritedWidget changed, because it's immutable and we can only chage it in some rebuild...
InheritedWidget is more useful for build method cases. When you want to get data from an ancestor inside your build method.
From the Flutter API: https://api.flutter.dev/flutter/widgets/BuildContext/findAncestorStateOfType.html
This should not be used from build methods, because the build context
will not be rebuilt if the value that would be returned by this method
changes. In general, dependOnInheritedWidgetOfExactType is more
appropriate for such cases. This method is useful for changing the
state of an ancestor widget in a one-off manner, for example, to cause
an ancestor scrolling list to scroll this build context's widget into
view, or to move the focus in response to user interaction.
Also by doing what you mention, you are coupling Widgets together which is not a good practice at all. Widgets are known to be able to moved from place to place without much modification.
There are many useful things that come from the Inherited Widget. Some of these things are very useful packages, I recommend that you take a look at them.
Provider package
InheritedWidget & InheritedModel
Redux
BLoC / Rx
GetIt
You can also take a look at the InheritedWidget documentation
Related
Maybe I don't understand the purpose of BloC or Provider but I'm confused as to why we would ever want to use them instead of using Flutter's built-in state management using the Stateful widget. I've just finished an app and can't remember a point where I wished I needed something more than the defaults. Can anyone clear things up for me?
There are a few reasons to use a BloC or Provider rather than Flutter's built-in setState:
BloC and Provider offer a more robust way to manage state.
BloC and Provider make it easier to update state across multiple widgets.
BloC and Provider can be used to manage async data.
BloC and Provider offer a more modular way to structure your code.
There are some case that you need BLoC to make you easier to define each state or condition that happening inside the application.
We will start discussing creating app like https://www.tokopedia.com/ (inspect element and go with phone size preview). You will see that between widget section tokopedia_ss there are some loading animations, and when the data load complete the widget loading animation changed to viewable widget (as user).
in bloc, you will make stateLoading(), stateComplete(data), stateFailed(data). and in the controller or screen you can describe what will happen when bloc state is stateLoading etc...
Creating this case with setstate is more complicated and make your code messy, also setstate will make phone render all the Build() code. not like BloC builder, you can define each widget or section.
So, when there are 10 sections, using Bloc you able to make it render each state but when using standard setstate it will render all the 10 sections in one time every state changes.
More information about BloC: article_about_BloC
I want to use InheritedWidget to access and change its data from anywhere in application.
I've read many articles about InheritedWidget, but I do not understand one of its behaviors.
Here it says that only widgets that are using InheritedWidget get rebuilt when data changes(which is exactly what I want).
But here it says that InheritedWidget is immutable and its data only changes when it is rebuilt itself!
So doesn't this make the whole widget tree below the InheritedWidget get rebuilt when the data changes?
How can I wrap the MaterialApp widget with InheritedWidget so I can change its data from anywhere in app and only rebuild a small Widget that is using InheritedWidget when the data changes?
I know I can implement this using provider package very easily, but in this part of application I want to use InheritedWidget if it's possible :)
An object or widget being immutable does not mean its values can't change.
You can declare a final List<widget> children, which is immutable since it is final, and still add and remove widgets from it. What is immutable is the reference.
When you use the InheritedWidget is the same. If a value changes it wont rebuild itself and all the tree below. Even it is actually changed and rebuilt, it does not necessarily rebuild all tree below, it'd happen only if the widget type or its child/children reference changed also.
I have one ParentWidget having two child widget.
I want to pass some callback action from FirstChild() to SecondChild() Widget without rebuild ParentWidget()like setState((){}).
I want to do because ParentWidget() has many widget. And this callback action continuously happen.
And continuously setState((){}) is not viable option for ParentWidget()
For example
setState((){}) call from FirstChild() than I want to rebuild SecondChild() without rebuild ParentWidget()
StatefulWidget is only useful in very simple business logic cases. I highly recommend that you have a look at Riverpod, where you can access a "state" from any widget, regardless of who its parent widget is. And because of how Riverpod is designed, it will not trigger any unnecessary rebuilds.
Sticking with StatefulWidget, you will need to use something like InheritedWidget as a parent of both widgets, and then have them both access it.
You can get help with state management solutions like Provider or Riverpod.
I may write an example code if you use Riverpod, but generally speaking, in such case, you need to place the state outside the Parent widget into some external variable. Then you can access and share it between both Children without rebuilding Parent.
I noticed that the build method gets called often in a flutter app.
I know that if the states of the page change in a statefulWidget, the build method gets triggered. But I also noticed that the build method is called even if nothing is changed in the app.
Considering the case where you leave the app to itself, is it normal for the build method to get called frequently? If so, why and how often?
Why
The build method is called any time you call setState, your widget's dependencies update, or any of the parent widgets are rebuilt (when setState is called inside of those).
Your widget will depend on any InheritedWidget you use, e.g. Theme.of(context), MediaQuery.of(context) etc.
This means that if the theme changes for example or the screen orientation swaps, your widget will also be rebuilt.
When you use widgets like MaterialApp, Scaffold etc. that are provided by the framework, your widget will be rebuilt a lot because these parent widgets depend on many InheritedWidget's and then are rebuilt, which causes your widget to be rebuilt as well.
How often
There is no number for how many rebuilds are "normal" as this completely depends on your tree size and most importantly widgets are in that tree. If you were to run runApp(Container()), there would be no rebuilds.
Just keep in mind that all of these rebuilds probably have a good reason to occur and Flutter is built for this, so you do not need to worry about this.
The only point you should start worrying is when you have constant rebuilds that are probably caused by some builder (which calls setState internally) you are using incorrectly.
Exactly when
The documentation lists all specific cases when rebuilds can occur:
After calling initState.
After calling didUpdateWidget.
After receiving a call to setState.
After a dependency of this State object changes (e.g., an InheritedWidget referenced by the previous build changes).
After calling deactivate and then reinserting the State object into the tree at another location.
Rebuilds from parent widgets
If you want to understand how InheritedWidget works, see this answer. It also touches when a rebuild in a parent widget causes the subtree to rebuild.
After calling initState.
After calling didUpdateWidget.
After receiving a call to setState.
After a dependency of this State object changes (e.g., an InheritedWidget referenced by the previous build changes).
After calling deactivate and then reinserting the State object into the tree at another location.
Read this for more info https://api.flutter.dev/flutter/widgets/State/build.html
Is it possible to do inter widget communication via something like a notification/event bus?
I need to be able to tell one widget to react to something that happened in another and didn't want to create a hard link.
The notification listener will only fire is if it is higher in the widget tree than both of the widgets so that isn't probably a viable solution.
There are lots of ways to do this depending on your use case.
You could have them be AnimatedWidgets that are passed a ValueNotifier or ChangeNotifier as the listenable. You can see this pattern in the Gallery's animation example.
You could use StreamBuilder to have your widgets rebuild automatically when new events come in on a Stream. There aren't a lot of examples of this in the main Flutter repo, but it's something that you're likely to need once you start using plugins or doing network I/O.
You could use a GlobalKey to get currentState and have one State call methods on the other. This is how snackbars work (example).
You can also extend InheritedWidget to provide widgets with information that wasn't passed as a constructor argument, and they'll automatically be marked for rebuild when that information changes. This is how Themes work, for example.
If you can provide more details on what your widgets do / what their relationship is, or ideally a code snippet I can help you decide which approach would make the most sense for your situation.