I do not understand the constructor part and static function part.
super?
dependOnInheritedWidgetOfExactType?
import 'comments_bloc.dart';
export 'comments_bloc.dart';
class CommentsProvider extends InheritedWidget {
final CommentsBloc commentsBloc;
CommentsProvider({Key key, Widget child})
: commentsBloc = CommentsBloc(), // what this line is doing.
super(key: key, child: child);
bool updateShouldNotify(_) => true;
//below code?
static CommentsBloc of(BuildContext context) {
return context
.dependOnInheritedWidgetOfExactType<CommentsProvider>()
.commentsBloc;
}
}
Step 1 : The dependOnInheritedWidgetOfExactType method enables a descendant widget to access the closest ancestor InheritedWidget instance enclosed in its BuildContext, in your code is CommentsProvider
Step 2 : And .commentsBloc means access this CommentsProvider 's attribute, in your code is final CommentsBloc commentsBloc;
Related
So, my code:
Type _typeOf<T>() => T;
abstract class BlocBase {
void dispose();
}
class BlocProvider<T extends BlocBase> extends StatefulWidget {
BlocProvider({
Key? key,
required this.child,
required this.bloc,
}) : super(key: key);
final Widget child;
final T bloc;
#override
_BlocProviderState<T> createState() => _BlocProviderState<T>();
static T of<T extends BlocBase>(BuildContext context) {
final type = _typeOf<_BlocProviderInherited<T>>();
_BlocProviderInherited<T> provider =
context.getElementForInheritedWidgetOfExactType<type>()?.widget;
return provider?.bloc;
}
}
class _BlocProviderState<T extends BlocBase> extends State<BlocProvider<T>> {
#override
void dispose() {
widget.bloc.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return new _BlocProviderInherited<T>(
bloc: widget.bloc,
child: widget.child,
);
}
}
class _BlocProviderInherited<T> extends InheritedWidget {
_BlocProviderInherited({
Key? key,
required Widget child,
required this.bloc,
}) : super(key: key, child: child);
final T bloc;
#override
bool updateShouldNotify(_BlocProviderInherited oldWidget) => false;
}
The offending line is this one:
_BlocProviderInherited<T> provider =
context.getElementForInheritedWidgetOfExactType<type>()?.widget;
And throws the error:
A value of type 'Widget?' can't be assigned to a variable of type '_BlocProviderInherited<T>'.
Edit: Additionally, it is throwing an error on the next line:
return provider?.bloc;
Error:
A value of type 'T?' can't be returned from the method 'of' because it has a return type of 'T'.
This is previously working code from my published app that no longer works after upgrading flutter from a quite old version.
Anyone know what it wants from me?
Edit: Have included full code, as referenced functions were not previously shown.
_BlocProviderInherited<T> provider =
context.getElementForInheritedWidgetOfExactType<type>()?.widget;
This line fails because the variable types don't match. A Widget? is not a _BlocProviderInherited<T>. My guess is that the extends InheritedWidget used to mean that _BlocProviderInherited<T> had a type of Widget, but now (based on the InheritedWidget documentation and the method documentation) that is not the case.
A value of type 'T?' can't be returned from the method 'of' because it has a return type of 'T'.
This error is caused by trying to return a variable that can be null from a method that only returns non-null variables. Flutter has changed a lot between major releases, including adding null safety. To fix it, change that line to return provider!.bloc; or provide a default bloc after: return provider?.bloc ?? <default value here>. Either way the returned value won't be null.
In Dart/Flutter I need that a closure / arrow function passed to a class instance would be able to use a variable of that class instance. Is there a way?
For example, I have a widget that will have a context in build method, as usual. I need to pass a closure to the widget and the closure needs to use that context.
If the class is yours then you can do
class MyWidget extends StatelessWidget {
final void Function(BuildContext) closure;
const MyWidget({required this.closure, Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
closure(context);
return ...
}
}
void closure(BuildContext context) {
// called from MyWidget, context is also from there.
}
// pass function to class
const MyWidget(closure: closure);
I got notification warning (Not Error) about Use key in widget constructors. let say I have stateless class like this :
class TeaTile extends StatelessWidget {
final TheTea? tea;
const TeaTile({this.tea}); //the warning in hire!
#override
Widget build(BuildContext context) {
return Container();
}
}
the basic stateless format has a key like this :
class TeaTile extends StatelessWidget {
const TeaTile({ Key? key }) : super(key: key); //this one
#override
Widget build(BuildContext context) {
return Container();
}
}
I know how to disable the key rule use_key_in_widget_constructors: false. but I don't want to do it. so, how I add key in
final TheTea? tea;
const TeaTile({this.tea});
to solve the warning notification?
Update for Dart 2.17 using Super Initializers:
final TheTea? tea;
const TeaTile({ super.key, this.tea });
The super keyword in a constructor is a shortcut for the method below.
Older Dart versions:
final TheTea? tea;
const TeaTile({ Key? key, this.tea }) : super(key: key);
Basically a combination of both, you're still taking a named parameter key, that will pass it's value to the super constructor, and another named parameter tea that would set your final variable value.
After creating a Bloc Provider class that extends an InheritedWidget, what is the difference between initializing the bloc instance variable inside the Provider constructor and initializing it while declaring the variable?
class CommentsProvider extends InheritedWidget {
final CommentsBloc bloc;
CommentsProvider({Key key, Widget child})
: bloc = CommentsBloc(),
super(key: key, child: child);
}
class CommentsProvider extends InheritedWidget {
final CommentsBloc bloc = CommentsBloc();
CommentsProvider({Key key, Widget child})
: super(key: key, child: child);
}
These two are strictly equivalent, but both options are bad.
You should not create mutate data inside an Inheritedwidget.You could easily loose your state and it is considered bad practice.
Instead consider wrapping your Inheritedwidge into a StatefulWidget, or use a package such as provider.
Using provider, you don't need to make such class anymore. Instead you can directly do:
Provider(
builder: (_) => CommentsBloc(),
dispose: (_, bloc) => bloc.dispose(),
child: Whatever(),
)
Is passing a GlobalKey down the tree using an InheritedWidget an antipattern? The stateful widget using that key is re-created (i.e. a new state this initState/disposed) every time its subtree is re-built.
My InheritedWidget looks like:
import 'package:flutter/material.dart';
import '../widgets/carousel.dart';
import '../widgets/panel/panel.dart';
class _CarouselKey extends GlobalObjectKey<CarouselState> {
const _CarouselKey(Object value) : super(value);
}
class _ProgressiveChatHeaderKey extends GlobalObjectKey<PanelScaffoldState> {
const _ProgressiveChatHeaderKey(Object value) : super(value);
}
class DimensionScopedKeyProvider extends InheritedWidget {
final _CarouselKey parallelBubbleCarouselKey;
final _ProgressiveChatHeaderKey progressiveChatHeaderKey;
final String keyString;
DimensionScopedKeyProvider({
Key key,
#required this.keyString,
#required Widget child,
}) : parallelBubbleCarouselKey = _CarouselKey(keyString),
progressiveChatHeaderKey = _ProgressiveChatHeaderKey(keyString),
super(key: key, child: child);
static DimensionScopedKeyProvider of(BuildContext context) {
return (context.inheritFromWidgetOfExactType(DimensionScopedKeyProvider)
as DimensionScopedKeyProvider);
}
#override
bool updateShouldNotify(DimensionScopedKeyProvider oldWidget) => oldWidget.keyString != keyString;
}
And this InheritedWidget is rendered with a constant keyString, meaning that 1) updateShouldNotify always returns false and 2) the hashCode of the GlobalKeys passed to my build methods via DimensionScopedKeyProvider.of() are always identical.
The stateful widget builds something like
GlobalKey<PanelScaffoldState> get _headerKey => //
DimensionScopedKeyProvider.of(context).progressiveChatHeaderKey;
// ...
PanelScaffold(
key: _headerKey,
// ...
)
When I change a property that affects the subtree that the PanelScaffold lives in, though, a new PanelScaffoldState is created and the old one is disposed, even though the widget tree hasn't changed structure and the _headerKey hasn't changed either.
I also able to solve this problem, but I have no idea why it works.
The solution is to cache the access to the GlobalKey in didChangeDependencies
#override
void didChangeDependencies() {
super.didChangeDependencies();
_headerKey ??= DimensionScopedKeyProvider.of(context).progressiveChatHeaderKey;
}
.... and now everything is working as expected again—the rebuilds re-parent the existing state.
Does anyone know why caching the getter to the GlobalKey is the key here?