I'm fetching some json data from the internet and displaying in a listview builder inside a stateless widget
Now I want to refresh the data using RefreshIndicator.
Do I need a stateful widget for this or can I manage to do this with a stateless widget?
My understanding:
If I don't need to refresh, I load the data from internet only on the app start up, So Stateless widget is enough
If I need to refresh, it involves user input, but I don't need to manage a state, I just need to re-run the build method (Which I plan to do by Navigating to the same page, in the onRefresh parameter of RefreshIndicator)
So do I need a stateful widget?
You must change the StatelessWidget to a StatefullWidget and use the function setState (){} to
If you need a RefreshIndicator to get again the jsondata from the internet you must need a StateFullWidget because u need to rebuild the page with the newdata.
There is no point in showing the indicator if you are not going to ask for new information.
Because you want to reduce the StatefulWidget instances, you can delegate the task of fetching data to a parent stateful widget.
You could pass a callback to perform the task of fetching data via the constructor of the StatelessWidget invoked whenever we want to refresh the data.
class _ParentWidgetState extends State<ParentWidget>{
...
Future<dynamic> _fetchData(){..}
...
Widget build(BuildContext){
return Container(
...
ChildWidget(onRefresh:_fetchData)
...
);
}
}
class ChildWidget extends StatelessWidget{
ChildWidget({Key? key,this.onRefresh}):super(key:key);
final Future<dynamic> Function() onRefresh;
...
#override
Widget build(BuildContext context){
return RefreshIndicator(
onRefresh:onRefresh,
child:..
);
...
}
}
The point is to delegate the task of loading the data to a parent StatefulWidget's state so you could use other mechanisms like ChangeNotifier to make the parent widget's state call the API and render after calling setState future in its own state.
Related
Using Flutter, I display a list of elements in an app.
I have a StatefulWidget (ObjectList) that holds a list of items in its State (ObjectListState).
The state has a method (_populateList) to update the list of items.
I want the list to be updated when a method (updateList) is called on the widget.
To achieve this, I save a reference (_state) to the state in the widget. The value is set in createState. Then the method on the state can be called from the widget itself.
class ObjectList extends StatefulWidget {
const ObjectList({super.key});
static late ObjectListState _state;
#override
State<ObjectList> createState() {
_state = ObjectListState();
return _state;
}
void updateList() {
_state._populateList();
}
}
class ObjectListState extends State<ObjectList> {
List<Object>? objects;
void _populateList() {
setState(() {
// objects = API().getObjects();
});
}
// ... return ListView in build
}
The problem is that this raises a no_logic_in_create_state warning. Since I'm not "passing data to State objects" I assume this is fine, but I would still like to avoid the warning.
Is there a way to do any of these?
Saving the reference to the state without violating no_logic_in_create_state.
Accessing the state from the widget, without saving the reference.
Calling the method of the state from the outside without going through the widget.
It make no sense to put the updateList() method in the widget. You will not be able to call it anyway. Widgets are part of a widget tree, and you do not store or use a reference to them (unlike in other frameworks, such as Qt).
To update information in a widget, use a StreamBuilder widget and create the widget to be updated in the build function, passing the updated list to as a parameter to the widget.
Then, you store the list inside the widget. Possibly this may then be implemented as a stateless widget.
I am trying to replace the use of Stateful widget with Getx. Most cases, I do not need it, however, when I am trying to create a list of cards widget, I find it hard to not to use the Stateful widget.
Obx(() {
getxA.updateA(name);
return Text(getxA.a());
})
RxString a = 'aaa'.obs;
updateA(String name) {
a(name);
}
When I have this Obx() - Text Widget inside the List Widget, it causes the error because each Text widget triggers updateA(String name) function.
It looks like every card is sharing one GetxController (getxA). Is there any way that to have each Text widget have its own GetxController? Or is it not possible in this case and I have to use the Stateful widget?
I am new to Flutter hooks and I have requirements that I have to use HookWidget instead of StatefulWidget. As I know, useState can only be declared within the build function.
Widget build(BuildContext context) {
final selectedBook = useState("");
return Container(
child: _buildBookListContainer(context)
)
}
Widget _buildBookListContainer(BuildContext context) {
//I will want to update the state value or read the state value in the child function
//how do I do that?
//Example: selectedBook.value = "xxx";
}
I tried passing down the state value as function arguments but it will not work. May I know that is it all HookWidget class will just write all components inside the build function without refractoring?
Presuming you're using Riverpod, watch my relatively short "building the counter app from scratch with my riverpod starter kit" at https://www.youtube.com/watch?v=0lPzFS5CAPs. It shows how to create a StateProvider, and then either reference it (with listen) or update it (no listen) for precise control of widget rebuilds.
I already known that build context can be used in StatefulWidget any where but only in build function when using Stateless Widget. There is so many content in widget need to reference the build context like Theme, showDialog,Navigator,Provider...
For Example, I have some code below in StatelessWidget:
#override
Widget build(BuildContext context){
...
_getFirstWidget();
...
}
...
Widget _getFirstWidget(){
return _getSecondWidget();
}
Widget _getSecondWidget(){
return _getThirdWidget();
}
Widget _getThirdWidget(){
// use build context here
}
...
If I want to use the build context at the end Widget, I think of 3 ways:
Pass the build context layer by layer
Convert to StatefulWidget
Convert the last widget to a Stateless Widget itself (and use the build context in build)
Why flutter make this restriction in StatelessWidget?
I'm not really sure but I think you want the use the BuildContext from the build method in the function '_getThirdWidget()'. You could just pass it as a parameter like below:
Widget _getThirdWidget(BuildContext context) {
// Use the context here
}
// Call the function like this in the parent widget
#override
Widget build(BuildContext context) {
return _getThirdWidget(context);
}
Let me know if this answers your question!
If you use the method of adding an argument to use context,
Almost every function needs a context argument
this is stupid behavior
StatelessWidget is inconvenient
I try to use StatelessWidget, but end up using Statefulwidget
I've got a widget that displays a classes' list, but that list changes (the content changes) over time by other elements and interactions of the program. How can the DisplayListWidget detect this? Do the elements that change this list have to communicate with the displaylistwidget?
EDIT: I'm familiair with stateful widgets and setState () {}. It's just that the data changes in the background (e.g. by a timer) so there's no reference from bussiness logic classes to widgets to even call setState.
If you would like to notify (rebuild) widgets when data changes, check out provider package.
There are some other options:
BLoC (Business Logic Component) design pattern.
mobx
Redux
Good luck
Try wrapping the display widget in a state widget, and then whenever you update the list, call setState(() { //update list here })
ex.
// this is the widget that you'd nest directly into the rest of your tree
class FooList extends StatefulWidget {
FooListState createState() => FooListState();
}
// this is the state you will want to call setState on
class FooListState extends State<FooList> {
Widget build(BuildContext context) {
return DisplayListWidget [...]
}
}
I would recommend following this flutter tutorial where they dynamically update a list
And to learn more about StatefulWidgets and States check this out: https://api.flutter.dev/flutter/widgets/StatefulWidget-class.html