{"id":427451,"date":"2024-07-26T09:00:43","date_gmt":"2024-07-26T09:00:43","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=427451"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=427451","title":{"rendered":"<span>Riverpod in Production<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>As a Flutter developer, I&#8217;ve always been on the lookout for efficient ways to manage app state and dependencies. In my journey, I&#8217;ve come across Riverpod, a powerful library that I like to think of as the Swiss Army knife of Flutter development. It offers elegant solutions for both state management and dependency injection, giving you the freedom to &#171;cook&#187; your app architecture just the way you like it.<\/p>\n<p>This flexibility, while powerful, can sometimes be overwhelming. The main challenge often lies in finding the optimal way to use Riverpod for your specific needs. In this post, I want to share with you a production-ready example from my own experience. We&#8217;ll explore Riverpod&#8217;s key features and then dive into a real-world example of how to implement a clean, modular dependency injection system.<\/p>\n<p>But before we dive in, let&#8217;s take a look at the dependencies we&#8217;ll be using. Here&#8217;s the <code>pubspec.yaml<\/code> file for our project:<\/p>\n<pre><code>name: riverpod_di_example description: \"Example of using Riverpod for managing application dependencies\"  publish_to: \"none\"  version: 1.0.0+1  environment:   sdk: \"&gt;=3.4.3 &lt;4.0.0\"  dependencies:   dio: ^5.5.0+1   flutter:     sdk: flutter   flutter_hooks: ^0.20.5   flutter_riverpod: ^2.5.1   hooks_riverpod: ^2.5.1   very_good_analysis: ^6.0.0  dev_dependencies:   flutter_test:     sdk: flutter  flutter:   uses-material-design: true<\/code><\/pre>\n<p>Now that we have our dependencies set up, let&#8217;s dive into what makes Riverpod such a versatile tool.<\/p>\n<h3>What is Riverpod?<\/h3>\n<p>Riverpod is a robust state management library for Flutter that offers a declarative approach to programming, easy implementation of complex UI patterns, and enhanced tooling support. Let&#8217;s look at its key features:<\/p>\n<h4>1. Declarative Programming<\/h4>\n<p>Riverpod allows developers to write business logic in a manner similar to Stateless widgets. This approach makes the code:<\/p>\n<ul>\n<li>\n<p>Easily reusable<\/p>\n<\/li>\n<li>\n<p>Highly composable<\/p>\n<\/li>\n<li>\n<p>More maintainable<\/p>\n<\/li>\n<\/ul>\n<p>A standout feature is its ability to automatically recompute network requests when necessary, streamlining data management in your application.<\/p>\n<h4>2. Simplified Implementation of Complex UI Patterns<\/h4>\n<p>With Riverpod, implementing common yet complex UI patterns becomes significantly easier. Features like:<\/p>\n<ul>\n<li>\n<p>Pull to refresh<\/p>\n<\/li>\n<li>\n<p>Search as you type<\/p>\n<\/li>\n<li>\n<p>Real-time updates<\/p>\n<\/li>\n<\/ul>\n<p>These can be implemented with just a few lines of code, greatly reducing development time and complexity.<\/p>\n<h4>3. Enhanced Tooling Support<\/h4>\n<p>Riverpod goes beyond just state management by providing robust tooling support:<\/p>\n<ul>\n<li>\n<p>It enhances the compiler to catch common mistakes at compile-time, turning them into compilation errors.<\/p>\n<\/li>\n<li>\n<p>Custom lint rules are provided to ensure code quality and consistency.<\/p>\n<\/li>\n<li>\n<p>Built-in refactoring options help maintain clean code as your project evolves.<\/p>\n<\/li>\n<li>\n<p>A command-line interface for generating documentation is included, aiding in project maintenance and onboarding.<\/p>\n<\/li>\n<\/ul>\n<h4>4. Comprehensive Feature Set<\/h4>\n<p>Riverpod offers a wide array of features that cater to various aspects of modern app development:<\/p>\n<ul>\n<li>\n<p>Declarative Programming<\/p>\n<\/li>\n<li>\n<p>Compile Safety<\/p>\n<\/li>\n<li>\n<p>Versatility (works in plain Dart environments)<\/p>\n<\/li>\n<li>\n<p>Custom Lint Rules<\/p>\n<\/li>\n<li>\n<p>Logging<\/p>\n<\/li>\n<li>\n<p>Native Network Request Support<\/p>\n<\/li>\n<li>\n<p>Type-safe Query Parameters<\/p>\n<\/li>\n<li>\n<p>Easily Combinable States<\/p>\n<\/li>\n<li>\n<p>Built-in Refactorings<\/p>\n<\/li>\n<li>\n<p>WebSocket Support<\/p>\n<\/li>\n<li>\n<p>Automatic Loading\/Error Handling<\/p>\n<\/li>\n<li>\n<p>Test Ready<\/p>\n<\/li>\n<li>\n<p>Built-in Support for Pull-to-Refresh<\/p>\n<\/li>\n<li>\n<p>Hot-Reload Support<\/p>\n<\/li>\n<li>\n<p>Documentation Generator<\/p>\n<\/li>\n<\/ul>\n<p>Now that we&#8217;ve covered the key features of Riverpod, let&#8217;s dive into a practical example of how to use it in a production environment for dependency injection.<\/p>\n<h3>Implementing Dependency Injection with Riverpod<\/h3>\n<p>One of the most powerful features of Riverpod is its ability to provide a clean and modular dependency injection system. Let&#8217;s look at how we can structure our DI setup using Dart&#8217;s <code>part<\/code> directive for better organization and maintainability.<\/p>\n<h4>Project Structure<\/h4>\n<p>For our example, we&#8217;ll use a Pokemon viewer app with the following structure for our DI setup:<\/p>\n<pre><code>lib\/ \u2514\u2500\u2500 src\/     \u2514\u2500\u2500 di\/         \u251c\u2500\u2500 di.dart         \u251c\u2500\u2500 manager_providers.dart         \u251c\u2500\u2500 repository_providers.dart         \u2514\u2500\u2500 view_model_providers.dart<\/code><\/pre>\n<h4>Main DI File<\/h4>\n<p>First, let&#8217;s look at the main <code>di.dart<\/code> file:<\/p>\n<pre><code class=\"dart\">\/\/ lib\/src\/di\/di.dart library di;  import 'package:flutter_riverpod\/flutter_riverpod.dart'; import 'package:riverpod_di_example\/src\/api\/api_manager.dart'; import 'package:riverpod_di_example\/src\/features\/pokemons_feed\/models\/pokemon.dart'; import 'package:riverpod_di_example\/src\/features\/pokemons_feed\/pokemons_feed_view_model.dart'; import 'package:riverpod_di_example\/src\/features\/pokemons_feed\/pokemons_repository.dart';  part 'manager_providers.dart'; part 'repository_providers.dart'; part 'view_model_providers.dart';  abstract final class Di {   static final viewModel = _ViewModelProviders();   static final manager = _ManagerProviders();   static final repository = _RepositoryProviders(); }<\/code><\/pre>\n<p>This file serves as the entry point for our DI setup. It imports necessary dependencies and uses the <code>part<\/code> directive to include other files that contain specific provider definitions.<\/p>\n<h4>Manager Providers<\/h4>\n<p>Next, let&#8217;s look at the <code>manager_providers.dart<\/code> file:<\/p>\n<pre><code class=\"dart\">\/\/ lib\/src\/di\/manager_providers.dart part of 'di.dart';  final class _ManagerProviders {   late final api = Provider((ref) =&gt; ApiManager()); }<\/code><\/pre>\n<p>This file contains providers for manager classes, such as the <code>ApiManager<\/code>.<\/p>\n<h4>Repository Providers<\/h4>\n<p>The <code>repository_providers.dart<\/code> file contains providers for repositories:<\/p>\n<pre><code class=\"dart\">\/\/ lib\/src\/di\/repository_providers.dart part of 'di.dart';  final class _RepositoryProviders {   late final pokemons = Provider(     (ref) =&gt; PokemonsRepository(       ref.watch(Di.manager.api),     ),   ); }<\/code><\/pre>\n<p>Here, we define a provider for the <code>PokemonsRepository<\/code>, which depends on the <code>ApiManager<\/code>.<\/p>\n<h4>ViewModel Providers<\/h4>\n<p>Finally, the <code>view_model_providers.dart<\/code> file contains providers for view models:<\/p>\n<pre><code class=\"dart\">\/\/ lib\/src\/di\/view_model_providers.dart part of 'di.dart';  final class _ViewModelProviders {   late final feed = StateNotifierProvider&lt;PokemonsFeedViewModel, List&lt;Pokemon&gt;&gt;(     (ref) =&gt; PokemonsFeedViewModel(       ref.watch(         Di.repository.pokemons,       ),     ),   ); }<\/code><\/pre>\n<p>This file defines a <code>StateNotifierProvider<\/code> for the <code>PokemonsFeedViewModel<\/code>, which depends on the <code>PokemonsRepository<\/code>.<\/p>\n<h4>Benefits of This Structure<\/h4>\n<ol>\n<li>\n<p><strong>Modularity<\/strong>: Each type of provider (managers, repositories, view models) is isolated in its own file, making the code easier to navigate and maintain.<\/p>\n<\/li>\n<li>\n<p><strong>Encapsulation<\/strong>: The <code>part<\/code> directive allows us to keep these provider definitions private to the <code>di.dart<\/code> file, preventing unauthorized access from other parts of the app.<\/p>\n<\/li>\n<li>\n<p><strong>Scalability<\/strong>: As the app grows, new providers can be easily added to the appropriate file without cluttering the main <code>di.dart<\/code> file.<\/p>\n<\/li>\n<li>\n<p><strong>Clear Dependencies<\/strong>: The structure makes it easy to see the dependency chain from view models down to managers.<\/p>\n<\/li>\n<li>\n<p><strong>Easy to Use<\/strong>: In other parts of the app, you can simply import the <code>di.dart<\/code> file and access all providers through the <code>Di<\/code> class.<\/p>\n<\/li>\n<\/ol>\n<h3>Using the DI Setup in Your App<\/h3>\n<p>To use this DI setup in your Flutter app, you would typically do the following:<\/p>\n<ol>\n<li>\n<p>Wrap your app with a <code>ProviderScope<\/code> in your <code>main.dart<\/code> file:<\/p>\n<\/li>\n<\/ol>\n<pre><code class=\"dart\">void main() {   runApp(     ProviderScope(       child: MyApp(),     ),   ); }<\/code><\/pre>\n<ol start=\"2\">\n<li>\n<p>In your widgets, use the <code>Consumer<\/code> widget or the <code>ref<\/code> parameter to access your providers:<\/p>\n<\/li>\n<\/ol>\n<pre><code class=\"dart\">class PokemonFeedPage extends ConsumerWidget {   @override   Widget build(BuildContext context, WidgetRef ref) {     final viewModel = ref.watch(Di.viewModel.pokemonsFeed.notifier);     final state = ref.watch(Di.viewModel.pokemonsFeed);      useEffect(       () {         viewModel.fetchPokemons();         return null;       },       [],     );      \/\/ Use viewModel and state to build your UI     \/\/ See the full code on Github   } }<\/code><\/pre>\n<h3>Conclusion<\/h3>\n<p>In my experience, Riverpod has proven to be an invaluable tool in my Flutter development toolkit. Its flexibility allows for clean, maintainable, and scalable code, especially when it comes to dependency injection and state management.<\/p>\n<p>The approach we&#8217;ve outlined in this post is just one way to leverage Riverpod&#8217;s power. It&#8217;s a method that has worked well for me in production environments, but remember &#8212; Riverpod is your Swiss Army knife. Feel free to adapt and modify this approach to best fit your project&#8217;s needs.<\/p>\n<p>If you want to dive deeper into Riverpod, I highly recommend checking out the official documentation at <a href=\"https:\/\/riverpod.dev\/\" rel=\"noopener noreferrer nofollow\">https:\/\/riverpod.dev\/<\/a>. It&#8217;s a goldmine of information and best practices.<\/p>\n<p>For a complete, working example of the code we&#8217;ve discussed in this post, you can visit the GitHub repository I&#8217;ve set up: <a href=\"https:\/\/github.com\/devasidmi\/riverpod_di_example\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/devasidmi\/riverpod_di_example<\/a>. Feel free to clone, fork, and experiment with it!<\/p>\n<p>Thank you for reading! I hope this post has given you some insights into how you can use Riverpod to streamline your Flutter development process. Happy coding!<\/p>\n<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/831544\/\"> https:\/\/habr.com\/ru\/articles\/831544\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>As a Flutter developer, I&#8217;ve always been on the lookout for efficient ways to manage app state and dependencies. In my journey, I&#8217;ve come across Riverpod, a powerful library that I like to think of as the Swiss Army knife of Flutter development. It offers elegant solutions for both state management and dependency injection, giving you the freedom to &#171;cook&#187; your app architecture just the way you like it.<\/p>\n<p>This flexibility, while powerful, can sometimes be overwhelming. The main challenge often lies in finding the optimal way to use Riverpod for your specific needs. In this post, I want to share with you a production-ready example from my own experience. We&#8217;ll explore Riverpod&#8217;s key features and then dive into a real-world example of how to implement a clean, modular dependency injection system.<\/p>\n<p>But before we dive in, let&#8217;s take a look at the dependencies we&#8217;ll be using. Here&#8217;s the <code>pubspec.yaml<\/code> file for our project:<\/p>\n<pre><code>name: riverpod_di_example description: \"Example of using Riverpod for managing application dependencies\"  publish_to: \"none\"  version: 1.0.0+1  environment:   sdk: \"&gt;=3.4.3 &lt;4.0.0\"  dependencies:   dio: ^5.5.0+1   flutter:     sdk: flutter   flutter_hooks: ^0.20.5   flutter_riverpod: ^2.5.1   hooks_riverpod: ^2.5.1   very_good_analysis: ^6.0.0  dev_dependencies:   flutter_test:     sdk: flutter  flutter:   uses-material-design: true<\/code><\/pre>\n<p>Now that we have our dependencies set up, let&#8217;s dive into what makes Riverpod such a versatile tool.<\/p>\n<h3>What is Riverpod?<\/h3>\n<p>Riverpod is a robust state management library for Flutter that offers a declarative approach to programming, easy implementation of complex UI patterns, and enhanced tooling support. Let&#8217;s look at its key features:<\/p>\n<h4>1. Declarative Programming<\/h4>\n<p>Riverpod allows developers to write business logic in a manner similar to Stateless widgets. This approach makes the code:<\/p>\n<ul>\n<li>\n<p>Easily reusable<\/p>\n<\/li>\n<li>\n<p>Highly composable<\/p>\n<\/li>\n<li>\n<p>More maintainable<\/p>\n<\/li>\n<\/ul>\n<p>A standout feature is its ability to automatically recompute network requests when necessary, streamlining data management in your application.<\/p>\n<h4>2. Simplified Implementation of Complex UI Patterns<\/h4>\n<p>With Riverpod, implementing common yet complex UI patterns becomes significantly easier. Features like:<\/p>\n<ul>\n<li>\n<p>Pull to refresh<\/p>\n<\/li>\n<li>\n<p>Search as you type<\/p>\n<\/li>\n<li>\n<p>Real-time updates<\/p>\n<\/li>\n<\/ul>\n<p>These can be implemented with just a few lines of code, greatly reducing development time and complexity.<\/p>\n<h4>3. Enhanced Tooling Support<\/h4>\n<p>Riverpod goes beyond just state management by providing robust tooling support:<\/p>\n<ul>\n<li>\n<p>It enhances the compiler to catch common mistakes at compile-time, turning them into compilation errors.<\/p>\n<\/li>\n<li>\n<p>Custom lint rules are provided to ensure code quality and consistency.<\/p>\n<\/li>\n<li>\n<p>Built-in refactoring options help maintain clean code as your project evolves.<\/p>\n<\/li>\n<li>\n<p>A command-line interface for generating documentation is included, aiding in project maintenance and onboarding.<\/p>\n<\/li>\n<\/ul>\n<h4>4. Comprehensive Feature Set<\/h4>\n<p>Riverpod offers a wide array of features that cater to various aspects of modern app development:<\/p>\n<ul>\n<li>\n<p>Declarative Programming<\/p>\n<\/li>\n<li>\n<p>Compile Safety<\/p>\n<\/li>\n<li>\n<p>Versatility (works in plain Dart environments)<\/p>\n<\/li>\n<li>\n<p>Custom Lint Rules<\/p>\n<\/li>\n<li>\n<p>Logging<\/p>\n<\/li>\n<li>\n<p>Native Network Request Support<\/p>\n<\/li>\n<li>\n<p>Type-safe Query Parameters<\/p>\n<\/li>\n<li>\n<p>Easily Combinable States<\/p>\n<\/li>\n<li>\n<p>Built-in Refactorings<\/p>\n<\/li>\n<li>\n<p>WebSocket Support<\/p>\n<\/li>\n<li>\n<p>Automatic Loading\/Error Handling<\/p>\n<\/li>\n<li>\n<p>Test Ready<\/p>\n<\/li>\n<li>\n<p>Built-in Support for Pull-to-Refresh<\/p>\n<\/li>\n<li>\n<p>Hot-Reload Support<\/p>\n<\/li>\n<li>\n<p>Documentation Generator<\/p>\n<\/li>\n<\/ul>\n<p>Now that we&#8217;ve covered the key features of Riverpod, let&#8217;s dive into a practical example of how to use it in a production environment for dependency injection.<\/p>\n<h3>Implementing Dependency Injection with Riverpod<\/h3>\n<p>One of the most powerful features of Riverpod is its ability to provide a clean and modular dependency injection system. Let&#8217;s look at how we can structure our DI setup using Dart&#8217;s <code>part<\/code> directive for better organization and maintainability.<\/p>\n<h4>Project Structure<\/h4>\n<p>For our example, we&#8217;ll use a Pokemon viewer app with the following structure for our DI setup:<\/p>\n<pre><code>lib\/ \u2514\u2500\u2500 src\/     \u2514\u2500\u2500 di\/         \u251c\u2500\u2500 di.dart         \u251c\u2500\u2500 manager_providers.dart         \u251c\u2500\u2500 repository_providers.dart         \u2514\u2500\u2500 view_model_providers.dart<\/code><\/pre>\n<h4>Main DI File<\/h4>\n<p>First, let&#8217;s look at the main <code>di.dart<\/code> file:<\/p>\n<pre><code class=\"dart\">\/\/ lib\/src\/di\/di.dart library di;  import 'package:flutter_riverpod\/flutter_riverpod.dart'; import 'package:riverpod_di_example\/src\/api\/api_manager.dart'; import 'package:riverpod_di_example\/src\/features\/pokemons_feed\/models\/pokemon.dart'; import 'package:riverpod_di_example\/src\/features\/pokemons_feed\/pokemons_feed_view_model.dart'; import 'package:riverpod_di_example\/src\/features\/pokemons_feed\/pokemons_repository.dart';  part 'manager_providers.dart'; part 'repository_providers.dart'; part 'view_model_providers.dart';  abstract final class Di {   static final viewModel = _ViewModelProviders();   static final manager = _ManagerProviders();   static final repository = _RepositoryProviders(); }<\/code><\/pre>\n<p>This file serves as the entry point for our DI setup. It imports necessary dependencies and uses the <code>part<\/code> directive to include other files that contain specific provider definitions.<\/p>\n<h4>Manager Providers<\/h4>\n<p>Next, let&#8217;s look at the <code>manager_providers.dart<\/code> file:<\/p>\n<pre><code class=\"dart\">\/\/ lib\/src\/di\/manager_providers.dart part of 'di.dart';  final class _ManagerProviders {   late final api = Provider((ref) =&gt; ApiManager()); }<\/code><\/pre>\n<p>This file contains providers for manager classes, such as the <code>ApiManager<\/code>.<\/p>\n<h4>Repository Providers<\/h4>\n<p>The <code>repository_providers.dart<\/code> file contains providers for repositories:<\/p>\n<pre><code class=\"dart\">\/\/ lib\/src\/di\/repository_providers.dart part of 'di.dart';  final class _RepositoryProviders {   late final pokemons = Provider(     (ref) =&gt; PokemonsRepository(       ref.watch(Di.manager.api),     ),   ); }<\/code><\/pre>\n<p>Here, we define a provider for the <code>PokemonsRepository<\/code>, which depends on the <code>ApiManager<\/code>.<\/p>\n<h4>ViewModel Providers<\/h4>\n<p>Finally, the <code>view_model_providers.dart<\/code> file contains providers for view models:<\/p>\n<pre><code class=\"dart\">\/\/ lib\/src\/di\/view_model_providers.dart part of 'di.dart';  final class _ViewModelProviders {   late final feed = StateNotifierProvider&lt;PokemonsFeedViewModel, List&lt;Pokemon&gt;&gt;(     (ref) =&gt; PokemonsFeedViewModel(       ref.watch(         Di.repository.pokemons,       ),     ),   ); }<\/code><\/pre>\n<p>This file defines a <code>StateNotifierProvider<\/code> for the <code>PokemonsFeedViewModel<\/code>, which depends on the <code>PokemonsRepository<\/code>.<\/p>\n<h4>Benefits of This Structure<\/h4>\n<ol>\n<li>\n<p><strong>Modularity<\/strong>: Each type of provider (managers, repositories, view models) is isolated in its own file, making the code easier to navigate and maintain.<\/p>\n<\/li>\n<li>\n<p><strong>Encapsulation<\/strong>: The <code>part<\/code> directive allows us to keep these provider definitions private to the <code>di.dart<\/code> file, preventing unauthorized access from other parts of the app.<\/p>\n<\/li>\n<li>\n<p><strong>Scalability<\/strong>: As the app grows, new providers can be easily added to the appropriate file without cluttering the main <code>di.dart<\/code> file.<\/p>\n<\/li>\n<li>\n<p><strong>Clear Dependencies<\/strong>: The structure makes it easy to see the dependency chain from view models down to managers.<\/p>\n<\/li>\n<li>\n<p><strong>Easy to Use<\/strong>: In other parts of the app, you can simply import the <code>di.dart<\/code> file and access all providers through the <code>Di<\/code> class.<\/p>\n<\/li>\n<\/ol>\n<h3>Using the DI Setup in Your App<\/h3>\n<p>To use this DI setup in your Flutter app, you would typically do the following:<\/p>\n<ol>\n<li>\n<p>Wrap your app with a <code>ProviderScope<\/code> in your <code>main.dart<\/code> file:<\/p>\n<\/li>\n<\/ol>\n<pre><code class=\"dart\">void main() {   runApp(     ProviderScope(       child: MyApp(),     ),   ); }<\/code><\/pre>\n<ol start=\"2\">\n<li>\n<p>In your widgets, use the <code>Consumer<\/code> widget or the <code>ref<\/code> parameter to access your providers:<\/p>\n<\/li>\n<\/ol>\n<pre><code class=\"dart\">class PokemonFeedPage extends ConsumerWidget {   @override   Widget build(BuildContext context, WidgetRef ref) {     final viewModel = ref.watch(Di.viewModel.pokemonsFeed.notifier);     final state = ref.watch(Di.viewModel.pokemonsFeed);      useEffect(       () {         viewModel.fetchPokemons();         return null;       },       [],     );      \/\/ Use viewModel and state to build your UI     \/\/ See the full code on Github   } }<\/code><\/pre>\n<h3>Conclusion<\/h3>\n<p>In my experience, Riverpod has proven to be an invaluable tool in my Flutter development toolkit. Its flexibility allows for clean, maintainable, and scalable code, especially when it comes to dependency injection and state management.<\/p>\n<p>The approach we&#8217;ve outlined in this post is just one way to leverage Riverpod&#8217;s power. It&#8217;s a method that has worked well for me in production environments, but remember &#8212; Riverpod is your Swiss Army knife. Feel free to adapt and modify this approach to best fit your project&#8217;s needs.<\/p>\n<p>If you want to dive deeper into Riverpod, I highly recommend checking out the official documentation at <a href=\"https:\/\/riverpod.dev\/\" rel=\"noopener noreferrer nofollow\">https:\/\/riverpod.dev\/<\/a>. It&#8217;s a goldmine of information and best practices.<\/p>\n<p>For a complete, working example of the code we&#8217;ve discussed in this post, you can visit the GitHub repository I&#8217;ve set up: <a href=\"https:\/\/github.com\/devasidmi\/riverpod_di_example\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/devasidmi\/riverpod_di_example<\/a>. Feel free to clone, fork, and experiment with it!<\/p>\n<p>Thank you for reading! I hope this post has given you some insights into how you can use Riverpod to streamline your Flutter development process. Happy coding!<\/p>\n<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/831544\/\"> https:\/\/habr.com\/ru\/articles\/831544\/<\/a><br \/><\/br><\/br><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-427451","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/427451","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=427451"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/427451\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=427451"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=427451"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=427451"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}