docs: add more examples and enhance docs with tutorials
Describe what scenario you think is uncovered by the existing examples/articles
- The current set of examples is a great starting point and covers many important use cases, but I think there's still room for more diverse and real-world examples.
- Additionally, the docs can be enhanced by adding tutorials instead of just linking back to the repository examples.
Describe why existing examples/articles do not cover this case
- More complex examples like - Firebase login or asynchronous CRUD operations would provide more value to the docs.
- The existing documentation primarily points to the repository, which might not be as beginner-friendly as structured tutorials. Here are some libraries that have included their examples as a form of tutorials
I'd like to get on that, if it's up for grabs š
From what I'm reading in the issue description, this could be achieved with:
- create tutorial section in the
docs - add entry for each item in
examples(counter,marvel,pub,random_number,stackoverflow,todo) - add tutorial for firebase login and asynchronous CRUD and maybe more?
Which tbh I would split into two PR's I guess š¤
Current examples are meh.
We need to make new examples, where every one of them demonstrates one specific thing. All current examples are pretty much the same thing, but with a different UI.
One Firebase integration would be cool.
Maybe one for go_router. It sounds commonly requested. Although you'll need my review for that.
And maybe one for shared_prefs or sqlite.
Then an example with a rest API
...
All those could be both in the form of "example" and "tutorial".
Don't do everything in one PR. One tutorial or example per PR. And do examples before tutorials, so that we can approve the code before having the English explanation :)
Thanks for the feedback and interest, everyone!
@BenAuerDev, since there are multiple tutorials and examples to create, we can split the work. For instance, Iād be happy to work on the Firebase login example and a corresponding tutorial. What do you think about focusing on the REST API example or go_router? We can align patterns together to maintain consistency.
Let me know your thoughts on how we can coordinate - I'm excited to collaborate!
Hey @thisissandipp I'd love to collaborate on this š šŖ thanks
Amazing š I'll start with REST API then.
After that we still need examples for:
go_routershared_prefsorsqlite
maye also serverpod?
And what about the basic examples like counter, timer and todo?
And what about the basic examples like
counter,timerandtodo?
I'd delete them.
maye also serverpod?
What would be the added value over the rest API example?
go_router has the added value of showcasing how to convert providers to ValueListenables
I'd delete them.
ok :) but don't you think some beginner friendly tutorials might be nice?
What would be the added value over the rest API example?
Sorry I meant serverpod_auth :) I wrote an article about combining it with riverpod and thought it might be a good addition but I guess it's not needed :)
So I'll start with rest API š
go_router has the added value of showcasing how to convert providers to ValueListenables
I might have some more questions about that once I'll start doing go_router :)
Hey guys,
I found an example for handling REST Api that is short but (imho) demonstrates it quite well. But I'm keen to hear what you think :)
Example:
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
void main() {
runApp(ProviderScope(child: MyApp()));
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: UserListScreen(),
);
}
}
// Model
class User {
final int id;
final String name;
final String email;
User({required this.id, required this.name, required this.email});
factory User.fromJson(Map<String, dynamic> json) => User(
id: json['id'],
name: json['name'],
email: json['email'],
);
}
// API Repository
class UserRepository {
final Dio dio;
UserRepository(this.dio);
Future<List<User>> fetchUsers() async {
try {
final response =
await dio.get('https://jsonplaceholder.typicode.com/users');
return (response.data as List)
.map((userData) => User.fromJson(userData))
.toList();
} catch (e) {
throw Exception('Failed to load users');
}
}
}
// Providers
final dioProvider = Provider((ref) => Dio());
final userRepositoryProvider = Provider((ref) {
return UserRepository(ref.watch(dioProvider));
});
final usersProvider = AsyncNotifierProvider<UsersNotifier, List<User>>(() {
return UsersNotifier();
});
// Notifier for Users State
class UsersNotifier extends AsyncNotifier<List<User>> {
@override
Future<List<User>> build() async {
final repository = ref.read(userRepositoryProvider);
return repository.fetchUsers();
}
Future<void> refreshUsers() async {
state = const AsyncValue.loading();
state = await AsyncValue.guard(() async {
return ref.read(userRepositoryProvider).fetchUsers();
});
}
}
// User List Screen
class UserListScreen extends ConsumerWidget {
const UserListScreen({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final usersAsync = ref.watch(usersProvider);
return Scaffold(
appBar: AppBar(title: Text('Users')),
body: usersAsync.when(
data: (users) => RefreshIndicator(
onRefresh: () => ref.read(usersProvider.notifier).refreshUsers(),
child: ListView.builder(
itemCount: users.length,
itemBuilder: (context, index) {
final user = users[index];
return ListTile(
title: Text(user.name),
subtitle: Text(user.email),
);
},
),
),
error: (error, stack) => Center(child: Text('Error: $error')),
loading: () => Center(child: CircularProgressIndicator()),
),
);
}
}
Furthermore I was wondering how to organize the examples like:
- should the code for each example be in
main.dartor be separated in files and dirs? if yes what structure? - should we remove all platfrom directories before making PR (e.g.
/android,/ios,/linux,/windows,/macos)
Let me know if I forgot something :) that you think we should also take into account or something :)
should the code for each example be in main.dart or be separated in files and dirs? if yes what structure?
Put it in examples/<yourexample>/
I found an example for handling REST Api that is short but (imho) demonstrates it quite well. But I'm keen to hear what you think :)
Overall I think that's missing a "post" part.
As is, that's similar to what we have on the homepage:
nit:
- ref.read(usersProvider.notifier).refreshUsers(),
+ ref.refresh(usersProvider)
- final repository = ref.read(userRepositoryProvider);
- final repository = ref.watch(userRepositoryProvider);
body: usersAsync.when(
Don't use when. Use switch
@rrousselGit
Does using switch instead of when sound like a good idea currently?
I mean, with when, we ensure all states are handled, but with switch, removing AsyncError(: final error) ā Text('error: $error') won't trigger a complaint.
Put it in
examples/<yourexample>/
No that I understood :) I just wondered if we should simply have:
examples/<yourexample>/lib/main.dart
or
examples/<yourexample>/lib/main.dart
examples/<yourexample>/lib/src/providers.dart
examples/<yourexample>/lib/src/UserListScreen.dart
Overall I think that's missing a "post" part.
Noted I'll use an example that uses both GET and POST.
Thanks for the feedback šŖ š
If a single file is enough, do that. Fewer files is better. It's easier for folks to navigate in
I've just been told "wouldn't it be wonderful if riverpod.dev/docs/tutorials would include full CRUD example, just like the "your first riverpod app"?
Something quite simple, e.g. a TODO app, that involves:
- a get --> a provider
- a post --> make it a notifier, show a mutation
- a put --> show how to use mutation differently
- a delete --> use that chance to show optimistic updates
- persist it --> solve #3930 as well
Is that something we can proceed with?