Open SimonLab opened 3 years ago
As an exercise to understand how provides works I've updated the default counter flutter application:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() {
runApp(MyApp());
}
// create counter model extending ChangeNotifier
// to be able to use the notifyListeners function
class CounterModel extends ChangeNotifier {
int counter = 0;
String toString() => '$counter';
// move the increment function which was defined in the widget to the model
void increment() {
counter++;
// notify that the counter value has changed
notifyListeners();
}
// define a reset function
void reset() {
counter = 0;
notifyListeners();
}
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
// create the change notifier widget wihch use the counter model
home: ChangeNotifierProvider(
create: (context) => CounterModel(),
child: MyHomePageProvider(title: 'Flutter Demo Home Page')));
}
}
// The home page is now a stateless widget as
// all the changes are managed by provider
class MyHomePageProvider extends StatelessWidget {
MyHomePageProvider({Key key, this.title}) : super(key: key);
final String title;
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
// Create a first consumer of the model changes
Consumer<CounterModel>(
builder: (context, counter, child) {
return Text(
'${counter.counter}',
style: Theme.of(context).textTheme.headline4,
);
},
),
// Use Provider.of to get an instance of the counter model without having to read the counter value itself
// this avoid rebuilding the button each time the counter valiue change
RaisedButton(onPressed: Provider.of<CounterModel>(context).reset, child: Text('reset'),)
],
),
),
floatingActionButton: FloatingActionButton(
// call the increment function from the counter instance selected via Provider.of
onPressed: Provider.of<CounterModel>(context, listen: false).increment,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
I'm now updating the todolist application to remove the statefull widgets when not necessary and replacing them with provider models.
I've converted the todolist widget from stateful to stateless and use provider to manage the state (adding a new task to the list), see the commit: https://github.com/dwyl/flutter-todo-list-tutorial/pull/17/commits/22d39e3f85638ae5dda79eb47afbef66843761af. I've been looking at adding provider to each tasks but I don't think it will be useful in this case and using stateful widgets for the tasks might be easier to manage.
I'm looking at now using a FutureProvider to load the saved tasks from the devices. The async function to get the tasks from the shared preferences need to be call when the state is initialised with provider.
ref: https://github.com/dwyl/flutter-todo-list-tutorial/issues/21#issuecomment-742535367
Provider can be use to make it easier to manage the state of the application, in particular to listen to changes applied to the list of tasks (e.g add a new task to the list, toggle complete/uncomplete task from the list...). So instead of letting the widget managing their own state we can use provide to create one source for the state application which will define how to display the tasks.
see also https://flutter.dev/docs/development/data-and-backend/state-mgmt/simple