# Flutter Riverpod Tutorial Part 4: Modifier & Parameters

In this tutorial we'll explore various modifiers and parameters functionality in Riverpod. These following features help manage more complex state scenarios and optimize resource usage by automatically disposing of providers when they are no longer needed.

# Family:

The `family` modifier allows you to create a provider that takes parameters. <mark>This is useful when you need to create multiple instances of a provider with different parameters.</mark>

## Example: Fetching Posts by User ID with Family

We will modify our existing example from [Tutorial 3](https://harishkunchala.com/flutter-riverpod-tutorial-part-3-combining-providers) to fetch posts by user ID using the `family` modifier.

1. ### Create Posts by User ID Provider Using Family
    

Let's update our `basic_providers.part` to include a provider with the `family` modifier:

```dart
//Provider with family modifier
final postsByUserIdProvider =
    FutureProvider.family<List<Post>, int>((ref, userId) async {
  final response = await http.get(
      Uri.parse('https://jsonplaceholder.typicode.com/posts?userId=$userId'));

  if (response.statusCode == 200) {
    List jsonData = json.decode(response.body);

    return jsonData.map((post) => Post.fromJson(post)).toList();
  } else {
    throw Exception('Unable to fetch posts from $userId');
  }
});
```

2. ### Use Posts by User ID Provider in our `user_id_posts_page.dart`
    

Finally let's create the above page. Where we'll get the userId from DropDown and then we'll show the posts

```dart
class UserIdPostsPage extends ConsumerWidget {
  const UserIdPostsPage({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final usersListAsync = ref.watch(usersProvider);
    final selectedUser = ref.watch(selectedUserProvider);

    final postsAsyncValue = selectedUser == null
        ? const AsyncValue.data([])
        : ref.watch(postsByUserIdProvider(selectedUser.id));

    return Scaffold(
      appBar: AppBar(
        title: const Text('Users and Posts with Family'),
      ),
      body: Column(
        children: [
          usersListAsync.when(
            data: (users) {
              return DropdownButton<User>(
                hint: const Text('Select a User'),
                value: selectedUser,
                onChanged: (user) {
                  ref.read(selectedUserProvider.notifier).state = user;
                },
                items: users.map((user) {
                  return DropdownMenuItem<User>(
                    value: user,
                    child: Text(user.name),
                  );
                }).toList(),
              );
            },
            loading: () => const Center(child: CircularProgressIndicator()),
            error: (error, stack) => Text('Error: $error'),
          ),
          Expanded(
            child: postsAsyncValue.when(
              data: (posts) {
                return ListView.builder(
                  itemCount: posts.length,
                  itemBuilder: (context, index) {
                    final post = posts[index];
                    return ListTile(
                      title: Text(post.title),
                      subtitle: Text(post.body),
                    );
                  },
                );
              },
              loading: () => const Center(child: CircularProgressIndicator()),
              error: (error, stack) => Center(child: Text('Error: $error')),
            ),
          ),
        ],
      ),
    );
  }
}
```

3. ### Output:
    

Now we can observer the output here:

![Flutter Family](https://media2.giphy.com/media/v1.Y2lkPTc5MGI3NjExczE4ajdvc3J3bmR3bGE3Znh5b240YnNmOGZtamhmemFycGVqc2VwZSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/UHtW663iyfGE1tL6q1/giphy.gif align="center")

4. ### Source Code
    

You can find the source code for Riverpod family here: [riverpod family commit](https://github.com/khkred/go_router_riverpod_tutorials/commit/81718f2efc930eef438a8343cdd33a2d272fa498)

# AutoDispose:

The `AutoDispose` modifier ensures that the provider is automatically disposed of when it is no longer needed.

This is useful for optimizing resource usage, particularly for providers that <mark>hold onto resources like network connections or subscriptions.</mark>

## **Example: Fetching Posts by AutoDispose Provider**

1. ### Create an AutoDispose Provider
    

Let's update our `basic_providers.dart` to include an `autoDispose` provider:

```dart
final autoDisposePostsProvider =
    FutureProvider.autoDispose<List<Post>>((ref) async {
  final response =
      await http.get(Uri.parse('https://jsonplaceholder.typicode.com/posts'));

  if (response.statusCode == 200) {
    List jsonData = json.decode(response.body);

    return jsonData.map((post) => Post.fromJson(post)).toList();
  } else {
    throw Exception('Failed to load posts');
  }
});
```

2. ### Use AutoDispose Provider in a Page
    

Let's create `posts_auto_dispose_page.dart` to call our `autoDispose` provider

```dart
class PostsAutoDisposePage extends ConsumerWidget {
  const PostsAutoDisposePage({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final postsAutoDisposeAsyncValue = ref.watch(autoDisposePostsProvider);

    return Scaffold(
      appBar: AppBar(
        title: const Text('Posts with AutoDispose'),
      ),
      body: postsAutoDisposeAsyncValue.when(
          data: (posts) => ListView.builder(
                itemCount: posts.length,
                itemBuilder: (context, index) {
                  final post = posts[index];
                  return ListTile(
                    title: Text(post.title),
                    subtitle: Text(post.body),
                  );
                },
              ),
          error: (error, stackTrace) => Center(
                child: Text("Error: $error"),
              ),
          loading: () => const Center(
                child: CircularProgressIndicator(),
              )),
    );
  }
}
```

3. ### Output:
    

As we can see the posts auto dispose page works as intended

![Posts auto dispose page](https://media1.giphy.com/media/v1.Y2lkPTc5MGI3NjExc2xtYnNxdXFrNzBudGk3Z21seG01OG5mZWUzdzQ1ajU0c2E2dGlxZyZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/nhMGUVKDfpuBgFDbx8/giphy.gif align="center")

4. ### Source Code:
    

You can find the source code in this commit: [Riverpod: autoDispose commit](https://github.com/khkred/go_router_riverpod_tutorials/tree/189cbe61e2451132f8c5fa3c144a8bc681fa0a38)

## keepAlive:

The `keepAlive` modifier can be used alongside `autoDispose`.

<mark>It allows certain instances of the provider to be kept alive even when not in use, based on a condition.</mark>

### `keepAlive` with `autoDispose`:

We will create an `autoDispose` Users provider to keep it alive under certain conditions.

```dart
final autoDisposeKeepAliveUsersProvider =
    FutureProvider.autoDispose<List<User>>((ref) async {
  //Keeps this provider alive even when it's no longer being listened to
  ref.keepAlive();

  final response =
      await http.get(Uri.parse('https://jsonplaceholder.typicode.com/users'));

  if (response.statusCode == 200) {
    List jsonData = json.decode(response.body);

    return jsonData.map((user) => User.fromJson(user)).toList();
  } else {
    throw Exception('Unable to load users');
  }
});
```

### Source Code:

You can find the source Code for the entire tutorial in this branch: [riverpod\_parameters](https://github.com/khkred/go_router_riverpod_tutorials/tree/riverpod_parameters)
