Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Anatomy of Riverpod - 박제창 @MODUPOP

Anatomy of Riverpod - 박제창 @MODUPOP

[MODUPOPxFlutter Seoul] Anatomy of Riverpod 박제창
https://festa.io/events/3375
2023년 4월 18일

JaiChangPark

April 18, 2023
Tweet

More Decks by JaiChangPark

Other Decks in Programming

Transcript

  1. Anatomy of Riverpod - 박제창 MODUPOP x Flutter Seoul Version

    1.0 Anatomy of Riverpod Dreamus Company - 박제창 1
  2. Anatomy of Riverpod - 박제창 드림어스컴퍼니 박제창 (Dreamwalker) • Dreamus

    Company • Flutter Seoul - Organizer • GDG Golang Korea - Organizer • Github: JAICHANGPARK • Twitter: @jaichangpark • Linkedin
  3. Anatomy of Riverpod - 박제창 MODUPOP x Flutter Seoul Version

    1.0 TOC Flutter State management Riverpod Riverpod Graph Riverpod Generator Riverpod lint 9
  4. Anatomy of Riverpod - 박제창 Overview State management is a

    complex topic. If you feel that some of your questions haven’t been answered, or that the approach described on these pages is not viable for your use cases, you are probably right 10 Flutter State management
  5. Anatomy of Riverpod - 박제창 12 Flutter State management 상태관리

    언제&왜 사용하세요? 아니면 언제 사용될까요?
  6. Anatomy of Riverpod - 박제창 13 Flutter State management 화면의

    데이터를 잠시 저장 테마 변경 설정 상태 등등등
  7. Anatomy of Riverpod - 박제창 14 Flutter State management Flutter

    is declarative. This means that Flutter builds its user interface to reflect the current state of your app When the state of your app changes (for example, the user flips a switch in the settings screen), you change the state, and that triggers a redraw of the user interface. https://docs.flutter.dev/development/data-and-backend/state-mgmt/declarative
  8. Anatomy of Riverpod - 박제창 15 Flutter State management Frameworks

    from Win32 to web to Android and iOS typically use an imperative style of UI programming
  9. Anatomy of Riverpod - 박제창 16 Flutter State management Imperative

    Frameworks from Win32 to web to Android and iOS typically use an imperative style of UI programming Java Kotlin
  10. Anatomy of Riverpod - 박제창 17 Flutter State management •

    https://developer.android.com/jetpack/compose?gclid=CjwKCAjwue6hBhBVEiwA9YTx8M46jT7q0GQIEDDiIwGBm0Wpb1V5spsIfA im3kfFLEK4z90pN68AAxoCyRoQAvD_BwE&gclsrc=aw.ds&hl=ko • https://developer.android.com/jetpack/compose/mental-model?hl=ko
  11. Anatomy of Riverpod - 박제창 19 Flutter State management https://docs.flutter.dev/development/data-and-backend/state-mgmt/ephemeral-vs-app

    • User preferences • Login info • Notifications in a social networking app • The shopping cart in an e-commerce app • Read/unread state of articles in a news app • current page in a PageView • current progress of a complex animation • current selected tab in a BottomNavigationBar
  12. Anatomy of Riverpod - 박제창 20 Flutter State management Widget

    & State “Everything is a Widget” Flutter Widget = Immutable Widget != Life Cycle • StatelessWidget • StatefulWidget
  13. Anatomy of Riverpod - 박제창 21 Flutter State management Widget

    & State “Everything is a Widget” Flutter Widget = Immutable Widget != Life Cycle • StatelessWidget • StatefulWidget
  14. Anatomy of Riverpod - 박제창 23 Flutter State management initState()

    didChangeDependencies dirty build clean dispose setState didUpdateWidget State Lifecycle Construction
  15. Anatomy of Riverpod - 박제창 26 Scaffold Center Colum Text

    Text FAB setState() build() build() build() build()
  16. Anatomy of Riverpod - 박제창 31 Flutter State management https://docs.flutter.dev/development/data-and-backend/state-mgmt/intro

    void myTapHandler(BuildContext context) { var cartModel = somehowGetMyCartModel(context); cartModel.add(item); }
  17. Anatomy of Riverpod - 박제창 32 Flutter State management https://docs.flutter.dev/development/data-and-backend/state-mgmt/intro

    https://docs.flutter.dev/development/data-and-backend/state-mgmt/simple Widget build(BuildContext context) { var cartModel = somehowGetMyCartModel(context); return SomeWidget( // Just construct the UI once, using the current state of the cart. ); }
  18. Anatomy of Riverpod - 박제창 38 Flutter State management Provider

    Riverpod setState InheritedWidget & InheritedModel Redux Fish-Redux BLoC / Rx GetIt MobX Flutter Commands Binder GetX states_rebuilder Triple Pattern (Segmented State Pattern) solidart flutter_reactive_widget List of state management approaches
  19. Anatomy of Riverpod - 박제창 40 Flutter State management setState()

    Notify the framework that the internal state of this object has changed. https://api.flutter.dev/flutter/widgets/State/setState.html
  20. Anatomy of Riverpod - 박제창 41 Flutter State management InheritedWidget()

    Base class for widgets that efficiently propagate information down the tree. To obtain the nearest instance of a particular type of inherited widget from a build context, use BuildContext.dependOnInheritedWidgetOfExactType. Inherited widgets, when referenced in this way, will cause the consumer to rebuild when the inherited widget itself changes state. https://api.flutter.dev/flutter/widgets/InheritedWidget-class.html
  21. Anatomy of Riverpod - 박제창 42 Flutter State management Inherited

    Widgets Explained - Flutter Widgets 101 Ep. 3 InheritedWidgets | Decoding Flutter InheritedWidget()
  22. Anatomy of Riverpod - 박제창 43 Flutter State management Scope

    Model https://pub.dev/packages/scoped_model
  23. Anatomy of Riverpod - 박제창 44 Flutter State management BLoC

    Business Logic Component Flutter / AngularDart – Code sharing, better together (DartConf 2018)
  24. Anatomy of Riverpod - 박제창 47 Flutter State management Provider

    True: dependOnInheritedWidgetOfExactType False: getElementForInheritedWidgetOfExactType
  25. Anatomy of Riverpod - 박제창 48 Flutter State management Provider

    Pragmatic State Management in Flutter (Google I/O'19)
  26. Anatomy of Riverpod - 박제창 49 Flutter State management Provider

    Remi Rousselet Provider: https:/ /github.com/rrousselGit/provider Riverpod: https:/ /github.com/rrousselGit/riverpod Freezed: https:/ /github.com/rrousselGit/freezed etc..
  27. Anatomy of Riverpod - 박제창 56 Riverpod 0 1 2

    3 4 5 6 7 P R O V I D E R R I V E R P O D 1 4 3 6 7 0 2 5
  28. Anatomy of Riverpod - 박제창 57 Riverpod 0 1 2

    3 4 5 6 7 P R O V I D E R R I V E R P O D 1 4 3 6 7 0 2 5
  29. Anatomy of Riverpod - 박제창 58 Riverpod 0 1 2

    3 4 5 6 7 P R O V I D E R R I V E R P O D 1 4 3 6 7 0 2 5 Anagram
  30. Anatomy of Riverpod - 박제창 59 Riverpod A Reactive State-Management

    and Dependency Injection Framework A Reactive Caching and Data-binding Framework
  31. Anatomy of Riverpod - 박제창 60 Riverpod Motivation Modern applications

    rarely come with all the information necessary to render their User Interface. Instead, the data is often fetched asynchronously from a server. The problem is, working with asynchronous code is hard. Although Flutter comes with some way to store state, it doesn't do much besides that. Thus, a number of challenges remain unsolved: • Asynchronous requests need to be cached locally, as it would be unreasonable to re-execute them whenever the UI refreshes. • Since we have a cache, our cache could get out of date if we're not careful. • We also need to handle errors and loading states
  32. Anatomy of Riverpod - 박제창 61 Riverpod Motivation • Reading

    objects is now compile-safe. No more runtime exception. • It makes the provider pattern more flexible, which allows supporting commonly requested features like: a. Being able to have multiple providers of the same type. b. Disposing the state of a provider when it is no longer used. c. Have computed states d. Making a provider private. • Simplifies complex object graphs. It is easier to depend on asynchronous state. • Makes the pattern independent from Flutter
  33. Anatomy of Riverpod - 박제창 62 Riverpod Motivation • Reading

    objects is now compile-safe. • No more runtime exception. - 사용자 & 고객 - 어? 화면이 회색으로 아무것도 안 보여요.. 😡 - 앱 삭제 - 리뷰 영향 - 서비스 이미지 영향
  34. Anatomy of Riverpod - 박제창 66 Riverpod Types of Providers

    Provider Type Provider Create Function Example Use Case Provider ( fully immutable.) Returns any type A service class / computed property (filtered list) StateProvider Returns any type A filter condition / simple state object FutureProvider Returns a Future of any type A result from an API call StreamProvider Returns a Stream of any type A stream of results from an API StateNotifierProvider Returns a subclass of StateNotifier A complex state object that is immutable except through an interface ChangeNotifierProvider Returns a subclass of ChangeNotifier A complex state object that requires mutability (Async)NotifierProvider - New 2.0
  35. Anatomy of Riverpod - 박제창 67 Riverpod Counter App Migration

    → FAB 을 누르면 숫자가 1씩 증가하는
  36. Anatomy of Riverpod - 박제창 68 Riverpod Counter App Migration

    flutter pub add flutter_riverpod dev:custom_lint dev:riverpod_lint riverpod_annotation dev:build_runner dev:riverpod_generator
  37. Anatomy of Riverpod - 박제창 70 Riverpod Counter App Migration

    아까 어디서 본거같은데~? 기억나시죠?
  38. Anatomy of Riverpod - 박제창 72 Riverpod Counter App Migration

    final _counterProvider = StateProvider((ref) => 0); 2. State 정의하기 2.1 StateProvider 사용 (cuz.. Simple value)
  39. Anatomy of Riverpod - 박제창 73 Riverpod Counter App Migration

    Provider Type Provider Create Function Example Use Case Provider Returns any type A service class / computed property (filtered list) StateProvider Returns any type A filter condition / simple state object FutureProvider Returns a Future of any type A result from an API call StreamProvider Returns a Stream of any type A stream of results from an API StateNotifierProvider Returns a subclass of StateNotifier A complex state object that is immutable except through an interface ChangeNotifierProvider Returns a subclass of ChangeNotifier A complex state object that requires mutability (Async)NotifierProvider - New 2.0
  40. Anatomy of Riverpod - 박제창 74 Riverpod Counter App Migration

    StateProvider exists primarily to allow the modification of simple variables by the User Interface. The state of a StateProvider is typically one of: • an enum, such as a filter type • a String, typically the raw content of a text field • a boolean, for checkboxes • a number, for pagination or age form fields You should not use StateProvider if: • your state needs validation logic • your state is a complex object (such as a custom class, a list/map, ...) • the logic for modifying your state is more advanced than a simple count++. https://docs-v2.riverpod.dev/docs/providers/state_provider
  41. Anatomy of Riverpod - 박제창 78 Riverpod Counter App Migration

    4. State 업데이트 (FAB tab action) ref.read ⇒ listening 없이 Provider를 읽어올때 사용
  42. Anatomy of Riverpod - 박제창 79 Riverpod Counter App Migration

    App ProviderScope MaterialApp ConsumerWidget Scaffold Column Text Consumer Fab Text Tab! ref.read(counterPr ovider.notifier).stat e++ sub ref.watch(counterProvider)
  43. Anatomy of Riverpod - 박제창 80 Riverpod Provider 읽기 final

    provider = Provider((ref) { // use ref to obtain other providers final repository = ref.watch(repositoryProvider); return SomeValue(repository); }) final counterProvider = StateNotifierProvider<Counter, int>((ref) { return Counter(ref); }); class Counter extends StateNotifier<int> { Counter(this.ref): super(0); final Ref ref; void increment() { // Counter can use the "ref" to read other providers final repository = ref.read(repositoryProvider); repository.post('...'); } }
  44. Anatomy of Riverpod - 박제창 81 Riverpod Provider 읽기 final

    counterProvider = StateNotifierProvider<Counter, int>((ref) => Counter(ref)); final anotherProvider = Provider((ref) { ref.listen<int>(counterProvider, (int? previousCount, int newCount) { print('The counter changed $newCount'); }); // ... });
  45. Anatomy of Riverpod - 박제창 82 Riverpod Provider 읽기 final

    counterProvider = StateNotifierProvider<Counter, int>((ref) => Counter(ref)); class HomeView extends ConsumerWidget { const HomeView({Key? key}): super(key: key); @override Widget build(BuildContext context, WidgetRef ref) { ref.listen<int>(counterProvider, (int? previousCount, int newCount) { print('The counter changed $newCount'); }); return Container(); } }
  46. Anatomy of Riverpod - 박제창 83 Riverpod Provider 읽기 Widget

    build(BuildContext context, WidgetRef ref) { AsyncValue<User> user = ref.watch(userProvider); return user.when( loading: () => const CircularProgressIndicator(), error: (error, stack) => const Text('Oops'), data: (user) => Text(user.name), ); }
  47. Anatomy of Riverpod - 박제창 84 Riverpod FutureProvider final configProvider

    = FutureProvider<Configuration>((ref) async { final content = json.decode( await rootBundle.loadString('assets/configurations.json'), ) as Map<String, Object?>; return Configuration.fromJson(content); }); Widget build(BuildContext context, WidgetRef ref) { AsyncValue<Configuration> config = ref.watch(configProvider); return config.when( loading: () => const CircularProgressIndicator(), error: (err, stack) => Text('Error: $err'), data: (config) { return Text(config.host); }, ); }
  48. Anatomy of Riverpod - 박제창 85 Riverpod StreamProvider - Usage

    example: live chat using sockets final chatProvider = StreamProvider<List<String>>((ref) async* { final socket = await Socket.connect('my-api', 4242); ref.onDispose(socket.close); var allMessages = const <String>[]; await for (final message in socket.map(utf8.decode)) { allMessages = [...allMessages, message]; yield allMessages; } });
  49. Anatomy of Riverpod - 박제창 86 Riverpod StreamProvider - Usage

    example: live chat using sockets Widget build(BuildContext context, WidgetRef ref) { final liveChats = ref.watch(chatProvider); return liveChats.when( loading: () => const CircularProgressIndicator(), error: (error, stackTrace) => Text(error.toString()), data: (messages) { return ListView.builder( reverse: true, itemCount: messages.length, itemBuilder: (context, index) { final message = messages[index]; return Text(message); }, ); }, ); }
  50. Anatomy of Riverpod - 박제창 87 Riverpod StateNotifierProvider → (v2.0)

    NotifierProvider class TodosNotifier extends StateNotifier<List<Todo>> { TodosNotifier(): super([]); void addTodo(Todo todo) { state = [...state, todo]; } // Let's allow removing todos void removeTodo(String todoId) { state = [ for (final todo in state) if (todo.id != todoId) todo, ]; } }
  51. Anatomy of Riverpod - 박제창 88 Riverpod StateNotifierProvider → (v2.0)

    NotifierProvider final todosProvider = StateNotifierProvider<TodosNotifier, List<Todo>>((ref) { return TodosNotifier(); });
  52. Anatomy of Riverpod - 박제창 89 Riverpod ProviderObserver ProviderObserver listens

    to the changes of a ProviderContainer. • didAddProvider is called every time a provider was initialized, and the value exposed is value. • didDisposeProvider is called every time a provider was disposed. • didUpdateProvider is called every time by providers when they emit a notification.
  53. Anatomy of Riverpod - 박제창 90 Riverpod ProviderObserver ProviderObserver listens

    to the changes of a ProviderContainer. class Logger extends ProviderObserver { @override void didUpdateProvider( ProviderBase<Object?> provider, Object? previousValue, Object? newValue, ProviderContainer container, ) { print(''' { "provider": "${provider.name ?? provider.runtimeType}", "newValue": "$newValue" }'''); } } void main() { runApp( ProviderScope( observers: [Logger()], child: const MyApp()), ); } observer는 여러개 가능 Debugging시 매우 유용
  54. Anatomy of Riverpod - 박제창 91 Riverpod Riverpod Graph WIP

    https://mermaid.js.org/#/ https://github.com/rrousselGit/riverp od/tree/master/packages/riverpod_ graph
  55. Anatomy of Riverpod - 박제창 93 Riverpod Riverpod Graph -

    WIP https://mermaid.js.org/#/ flowchart TB subgraph Arrows direction LR start1[ ] -..->|read| stop1[ ] style start1 height:0px; style stop1 height:0px; start2[ ] --->|listen| stop2[ ] style start2 height:0px; style stop2 height:0px; start3[ ] ===>|watch| stop3[ ] style start3 height:0px; style stop3 height:0px; end subgraph Type direction TB ConsumerWidget((widget)); Provider[[provider]]; end
  56. Anatomy of Riverpod - 박제창 94 Riverpod Riverpod Graph -

    WIP https://mermaid.js.org/#/ flowchart TB subgraph Arrows direction LR start1[ ] -..->|read| stop1[ ] style start1 height:0px; style stop1 height:0px; start2[ ] --->|listen| stop2[ ] style start2 height:0px; style stop2 height:0px; start3[ ] ===>|watch| stop3[ ] style start3 height:0px; style stop3 height:0px; end subgraph Type direction TB ConsumerWidget ((widget)); Provider[[provider]]; end
  57. Anatomy of Riverpod - 박제창 95 Riverpod Riverpod Generator →

    code generation https://github.com/rrousselGit/riverpod/tree/master/packages/riverpod_generator https://pub.dev/packages/riverpod_generator
  58. Anatomy of Riverpod - 박제창 99 Riverpod Riverpod Generator →

    code generation generator로 StateProvider는 못 만드나요? 네, 그렇습니다. https://github.com/rrousselGit/riverpod/discussions/1725#discussioncomment-3797487
  59. Anatomy of Riverpod - 박제창 100 Riverpod Riverpod Generator →

    code generation AutoDisposeNotifierProvider
  60. Anatomy of Riverpod - 박제창 103 dev_dependencies: custom_lint: riverpod_lint: analyzer:

    plugins: - custom_lint Riverpod Riverpod lint dart run custom_lint
  61. Anatomy of Riverpod - 박제창 105 analyzer: plugins: - custom_lint

    custom_lint: rules: - missing_provider_scope: true Riverpod Riverpod lint dart run custom_lint
  62. Anatomy of Riverpod - 박제창 106 Riverpod Riverpod lint •

    Enable_all_lint_rules • Missing_provider_scope • provider_dependencies • Scoped_providers_should_specify_dependencies • Avoid_manual_providers_as_generated_provider_dependency • provider_parameters • avoid_public_notifier_properties • unsupported_provider_value • stateless_ref • generator_class_extends
  63. Anatomy of Riverpod - 박제창 107 Riverpod Will provider be

    deprecated/stop being supported? Not in the short term, no. ↓ Maybe.
  64. Anatomy of Riverpod - 박제창 108 Riverpod Provider likely will

    be deprecated. But that's because Riverpod is it's successor, and I actively work on Riverpod For the "Provider will be deprecated", there are two things to keep in mind: - I will write a tool to automatically migrate from Provider to Riverpod - I'm currently working on a Flutter PR to allow `http:/ /context.watch` in Riverpod (although unclear whether it'll pass) @Remi Rousselet, 2022.08.14
  65. Anatomy of Riverpod - 박제창 109 Summary 1. Flutter State

    Management a. Everything is a widget b. Widget = immutable c. State = Lifecycle 2. List of flutter state management a. setState() b. inheritedWidget c. Scope Model, BLoC, GetX, Provider, Riverpod…etc 3. Riverpod a. Hmmmm, Riverpod 2.0! b. Provider, StateProvider, FutureProvider, StreamProvider and NotifierProvider(new) c. Riverpod Graph(WIP), Generator, Lint!