Using a provider in a custom class flutter - flutter

I am creating a program that needs to use Provider to get values. I call my provider like below in a stateful widget
final user = Provider.of<Users>(context);
Now I would like to use the provider in a custom class
class UserInformation {
final user = Provider.of<Users>(context):
}
This won't work because context is not defined. kindly assist on how I can do this without using a BuildContext.
This is my class Users that I have on a separate dart file and use as a model for for my data streams.
class Users {
final String uid;
final String name;
final String department;
final String position;
Users({ this.uid, this.department, this.name, this.position });
}
This is the query I use to pull data from firestore
Stream<List<FormQuestions>> get userData{
return userCollection.where('name', isEqualTo: 'First Name').where('department', isEqualTo: 'department').snapshots()
.map(_userDataFromSnapshot);
}
I would like the name to be a variable that I get from say (user.name) from the model class. and the same for the department.
Thanks.

You can only access classes which are ChangeNotifiers in the descendant widgets in the tree below this provided ChangeNotifier because behind the scenes the Provider uses InheritedWidget (which uses context) to provide you with the ChangeNotifier you put up in the tree
So in your case there is no way to access the Users from UserInformation and you have to alter your code to make a workaround
Edit: this is a suggestion to achieve what you want if you are using this code inside a widget:
class UserInformation{
final User user;
UserInformation(this.user);
}
class SomeWidget extends StatefulWidget {
#override
_SomeWidgetState createState() => _SomeWidgetState();
}
class _SomeWidgetState extends State<SomeWidget> {
void someMethod(){
final User user = Provider.of<Users>(context);
UserInformation userInformation = UserInformation(user);
//do something
}
#override
Widget build(BuildContext context) {
return Container();
}
}

¡Hey! In the class you need to add "with ChangeNotifier":
class Users with ChangeNotifier {
final String uid;
final String name;
final String department;
final String position;
Users({ this.uid, this.department, this.name, this.position });
}
Hope help. Sorry for the english, yo hablo español. :D

Related

Why does flutter call its CLASSES as WIDGETS? Why not call it a class? why the term "widget" is used?

Widget is a class! But why not call it just class and not widget?
I know that every thing in the flutter is a widget and every class is a widget.
Why though?
Maybe call every class gadget or anything else?
I was wondering if my interviewer might ask me this question!
A widget is a class that has the build method:
#override
Widget build(BuildContext context) {
return Container(...);
}
A normal class doesn't have a build method.
You also can make a widget:
create a class that extends StatelessWidget or StatefulWidget
create a widget tree inside the build method:
#override
Widget build(BuildContext context) {
return Container(...); //Widget tree
}
(optional) create a constructor that gives you all the information you need:
var name;
var age;
var location;
//constructor
ClassName({this.name, this.age, this.location});
in the constructor you also can make things required:
var name;
var age;
var location;
//constructor
ClassName({#required this.name, this.age, this.location});
you put the constructor at the beginning of your class:
class WidgetName extends StatelessWidget {
//constructor
WidgetName({
#required this.name,
this.age,
this.location,
});
var name;
var age;
var location;
#override
Widget build(BuildContext context) {
return Container(...); //Widget tree
}
}
or extending StatefulWidget:
class WidgetName extends StatefulWidget {
var name;
var age;
var location;
//constructor
WidgetName({this.name, this.age, this.location});
#override
_WidgetNameState createState() => _WidgetNameState();
}
class _WidgetNameState extends State<WidgetName> {
//inside of this class you can get the data from the constructor like this: widget.name
#override
Widget build(BuildContext context) {
return Container(...);
}
}
and you can use the widget like a normal widget:
WidgetName(
name: "David",
age: 28,
location: "Sofia, Bulgaria",
),
I hope this answer helps you to understand the difference between a normal class and a widget!
Simply, a widget is any class that inherits from the Widget class, typically starting from StatefulWidget or StatelessWidget. A widget is expected to have a certain protocol... in particular, be part of the context tree and also be able to be moved in that tree. Most widgets contribute some view on the UI, but some don't, and are merely for settings like TextTheme.
every flutter class is a Widgdet not right !
every flutter class (Widget build) is a Widgdet is right .
class will never be a widget !
Widget it's more high level construction than class.
Class it's foundation.

Provide generic arguments to DocumentReferences in JsonConverter

I'm using json_serializable's JSONConverter interface to convert Firestore's DocumentReferences into valid JSON objects.
This is the JSON converter class. It tries to be generic:
class DocumentSerializer<T>
implements JsonConverter<DocumentReference<T>, DocumentReference<T>> {
const DocumentSerializer();
#override
DocumentReference<T> fromJson(DocumentReference<T> docRef) => docRef;
#override
DocumentReference<T> toJson(DocumentReference<T> docRef) => docRef;
}
And this is the usage of the annotation:
#JsonSerializable(explicitToJson: true)
class Recipe {
#DocumentSerializer<Recipe>()
final DocumentReference<Recipe> id;
#DocumentSerializer<User>()
final DocumentReference<User> authorId;
final String title;
final String description;
final String imageUrl;
final List<DocumentReference<User>> likes;
final List<String> ingredients;
final List<String> steps;
.
.
.
}
Unfortunately, this does not work. The build runner fails when it reaches the first usage of the annotation, which is the id field. Is there a way to provide generics to DocumentReferences in JsonConverter which can be serialized properly?
I found a workaround; albeit less elegant than what I'm aiming for. Turns out separate JsonConverters need to be created for each DocumentReference type.
For example, if I have an id field of type DocumentReference<Recipe> for the Recipe class , I would need to create the following JSON converter...
class RecipeSerializer
implements
JsonConverter<DocumentReference<Recipe>, DocumentReference<Recipe>> {
const RecipeSerializer();
#override
DocumentReference<Recipe> fromJson(DocumentReference<Recipe> json) => json;
#override
DocumentReference<Recipe> toJson(DocumentReference<Recipe> object) => object;
}
...and use it as such:
#JsonSerializable(explicitToJson: true)
class Recipe {
#RecipeSerializer()
final DocumentReference<Recipe> id;
#UserSerializer() // <- same goes for other types
final DocumentReference<User> authorId;
final String title;
final String description;
final String imageUrl;
final List<DocumentReference<User>> likes;
final List<String> ingredients;
final List<String> steps;
.
.
.
}
A bit more verbose, but I'll take it unless someone comes up with a more efficient answer.

Flutter Riverpod: Filter rebuilds with StateNotifier and .select()

This is my current state management solution
class UserState {
final int id;
final String name;
}
class UserNotifier extends StateNotifier<UserState> {
UserNotifier() : super(User(1, 'Pero Peric'));
}
final userNotifierProvider = StateNotifierProvider((ref) => UserNotifier());
I want to rebuild my UI only when the name changes not the id!
Riverpod provides a way to do this link but I can't get it working with my StateNotifier.
I would write it like this but it isn't working like this.
// inside Consumer widget
final userName = watch(userNotifierProvider.select((value) => value.state.name));
Can you refactor my code to work or propose another solution?
Any help is appreciated!
According to the doc, "this method of listening to an object is currently only supported by useProvider from hooks_riverpod and ProviderContainer.listen".
Try to create another provider, which you can use in UI.
final nameProvider = StateProvider<String>((ref) => ref.watch(userNotifierProvider.select((user) => user.name)));
class UserState {
UserState({
required this.id,
required this.name,
});
final int id;
final String name;
}
class UserNotifier extends StateNotifier<UserState> {
UserNotifier() : super(UserState(id: 1, name: 'Pero Peric'));
}
final userNotifierProvider =
StateNotifierProvider<UserNotifier, UserState>((ref) => UserNotifier());
In consumer,
final userName =
watch(userNotifierProvider.select((value) => value.name)); // value is the state

Is there any best practice of how to define the widget's properties visibility in Flutter?

In Java, according to the recommendations of Effective Java (Item 15 ["Minimize Mutability"] in the Second Edition and Item 13 ["Favor Immutability"] in the First Edition):
Fields are final and private.
If a field does not intend to be used externally, it's likely to set it to private, e.g.,
class CustomAppBar extends View {
public CustomAppBar(Context context, String title, Boolean centerTitle) {
super(context);
this.title = title;
this.centerTitle = centerTitle;
}
private final String title;
private final Boolean centerTitle;
}
But in Flutter framework, almost all Flutter widgets use properties as public property, like what I see in AppBar:
class AppBar extends StatefulWidget implements PreferredSizeWidget {
AppBar({
this.title,
this.centerTitle,
...
}): ...
final Widget title;
final bool centerTitle;
...
}
But based on the experience I learned from Java, I should make it more reasonable to change the properties to private, such like:
class CustomAppBar extends StatefulWidget implements PreferredSizeWidget {
CustomAppBar({
Widget title,
bool centerTitle,
}): _title = title,
_centerTitle = centerTitle;
final Widget _title;
final bool _centerTitle;
...
}
So I am curious, is there any best practice(effective) guide of the visibility of the properties of Flutter widgets?
From Dart Documentation
Dart doesn’t have the keywords public, protected, and private. If an identifier starts with an underscore _, it’s private to its Class, so it is different than Java
So as per you code only:
// these are private entities inside your Class/Activity
final Widget _title;
final bool _centerTitle;

Flutter: Undefined name Try correcting the name to one that is defined, or defining the name

I am facing a few strange issues with Flutter. I do have very little knowledge about Flutter. I am learning it.
class ViewOtherProfile extends StatefulWidget {
final String userName;
final int points;
const ViewOtherProfile({
#required this.userName,
#required this.points,
});
You can see i am getting userName and Points data as argument.
I want to print this argument in the page. Like this
class _ViewOtherProfileState extends State<ViewOtherProfile> {
..........
void initState(){
print(points);
deviceInfo();
super.initState();
print(userName);
]);
}
............
Now problem is i am getting error.
Undefined name 'userName'.
Try correcting the name to one that is defined, or defining the name.
Any reason why i am getting this error and how i can resolve it.
Thanks to #jamesdlin
I tried to put it like this
print(ViewOtherProfile.userName);
but now i am getting another error.
Instance member 'userName' can't be accessed using static access.
There are two main types of widgets in Flutter. StatelessWidget and StatefullWidget. A StatelessWidget is built only one when the UI builds and is never rebuilt. Meanwhile, a StatefulWidget can be rebuilt every time if a call for setState is made.
Hence, for a StatefulWiget, there is a need to track the state of the class by extending the main class with a State class.
You have to note that the scope of variables in those two types of widgets can vary. For example...
class ExampleStateless extends StatelessWidget {
final String userName;
final int points;
const ExampleStateless({
#required this.userName,
#required this.points,
});
#override
Widget build(BuildContext context){
print(userName); print(points);
return Something();
}
}
Note that for the stateful widget, there are two classes and each class has its scope. The superclass ExampleStateful can share its scope to its subclass _ExampleStatefulState via the widget
class ExampleStateful extends StatefulWidget {
final String userName;
final int points;
Static final string id = "exampleState";
const ExampleStatefull({
#required this.userName,
#required this.points,
});
// scope 1
#override
_ExampleStatefulState createState() => _ExampleStatefulState();
}
class _ExampleStatefulState extends State<ExampleStateful>{
// scope 2
final String userName2 = null;
#override
void initState(){
super.initState();
print(widget.userName);
print(userName2);
print(ExampleStateful.id); // you can do this only if variable is static.
}
}
What is in scope 1 can be accessed in scope 2 via the widget properties. eg print(widget.userName); instead of print(userName);