diff --git a/CHANGELOG.md b/CHANGELOG.md index 4427c2ba..f5929fb3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,51 @@ # Reactter +## 5.1.0 + +### Enhancements + +- **feat(framework):** Implement hook register. + - Add hook register logic for attaching `ReactterState` defined into `ReactterHook`. + - Refactor hooks to implement hook register. +- **feat(framework):** Add `lazy` method and make `isInstanceBuilding` variable as public. +- **feat(extensions):** Add `ReactterStateListExtension` with `when` method. +- **feat(hooks):** Add `UseCompute` hook. +- **feat(widget, test):** Add `ReactterConsumer` widget. + +### Internal + +- **build(example):** Use `reactter_lint`. +- **build(widgets):** Remove unnecesary import. +- **doc:** Fix `ReactterInstanceNotFoundException` documentation. +- **refactor(framework):** Export `ReactterInstance`. +- **doc(example):** Add and remove some concepts from main. +- **refactor(example):** Remove late keyword form some hooks. +- **refactor(example):** Implement play and stop animation. +- **refactor(framework):** Rename `_RegisterHook` to `HookRegister`. +- **test:** Add `ReactterStateListExtension` test and other adjustments. +- **refactor(widgets):** Make `ReactterConsumer.builder` required. +- **fix(framework):** Add instance attached validation before `UseCompute` is disponsed. +- **refactor(extensions):** Use `UseCompute` type on `when` method. +- **test:** Add `UseCompute` test and other adjustments. +- **build(example):** Change folder structure. +- **build:** Change folder structure for `flutter_reactter` package. + - Move all files to `src`. + - Rename `ReactterTypes` to `types`. + - `engine` was separated into `extensions`, `framework` and `types`. + - Change folder structure of `test`. +- **build:** Change folder structure for `reactter` package. + - Move all files to `src`. + - Rename `ReactterTypes` to `types`. + - `core` was separated into `framework`, `objs`, `signals`, `lifecycle`, `types`. + - Change folder structure of `test`. +- **refactor(core, widgets):** Implement Reactter event to Signal generic. + - Remove `ReactterSignalProxy`. + - Move `Obj`, `Signal` to other folder. + - Refactor `ReactterWatcher` to the new changes. +- **refactor(core):** Remove `ReactterNotifyManager`. + - `ReactterNotifyManager` is no longer used, all its methods were moved to `ReactterState`. + - `Lifecycle` enum was move to new file(`lifecycle.dart`). + ## 5.0.1 ### Internal diff --git a/README.md b/README.md index 0ea764ec..d0748420 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ ____ - 💧 **Adaptable** to any architecture. - ☢️ **Reactive state** using [Signal](#signal). - ♻️ **Reuse state** creating [custom hooks](#custom-hooks). -- 🪄 **No configuration** necessary. +- 🪄 **No configuration** and **no code generation** necessary. - 🎮 **Total control** to re-render widget tree. - 💙 **Dart or Flutter**, supports the latest version of Dart. @@ -79,6 +79,7 @@ See more examples [here](https://zapp.run/pub/flutter_reactter)! - [Different between Signal and UseState](#different-between-signal-and-usestate) - [UseAsyncState](#useasyncstate) - [UseReducer](#usereducer) + - [UseCompute](#usecompute) - [Custom hooks](#custom-hooks) - [Dependency injection](#dependency-injection) - [Shortcuts to manage instances](#shortcuts-to-manage-instances) @@ -90,6 +91,7 @@ See more examples [here](https://zapp.run/pub/flutter_reactter)! - [Shortcuts to manage events](#shortcuts-to-manage-events) - [UseEvent](#useevent) - [UseEffect](#useeffect) + - [ReactterConsumer](#reactterconsumer) (`flutter_reactter`) - [ReactterWatcher](#reactterwatcher) (`flutter_reactter`) - [BuildContext extension](#buildcontext-extension) (`flutter_reactter`) - [Resources](#resources) @@ -172,6 +174,13 @@ import 'package:flutter_reactter/flutter_reactter.dart'; +And it is recommended to use +[![Reactter Lint](https://img.shields.io/pub/v/reactter_lint?color=1d7fac&labelColor=29b6f6&label=reactter_lint&logo=dart)](https://pub.dev/packages/reactter_lint) +which will help to encourage good coding practices and preventing frequent problems using the Reactter convensions. + +If you use Visual Studio Code, it is a good idea to use [Reactter Snippets]( +https://marketplace.visualstudio.com/items?itemName=CarLeonDev.reacttersnippets) for improving productivity. + ## About Reactter Reactter is a light and powerful solution for Dart and Flutter. It is composed of three main concepts that can be used together to create maintainable and scalable applications, which are: @@ -182,7 +191,7 @@ Reactter is a light and powerful solution for Dart and Flutter. It is composed o ## State management -In Reactter, state is understood as any object that extends[`ReactterState`](https://pub.dev/documentation/reactter/latest/core/ReactterState-mixin.html), which gives it features such as being able to store one or more values and to notify of its changes. +In Reactter, state is understood as any object that extends[`ReactterState`](https://pub.dev/documentation/reactter/latest/reactter/ReactterState-class.html), which gives it features such as being able to store one or more values and to notify of its changes. Reactter offers the following several state managers: @@ -190,16 +199,17 @@ Reactter offers the following several state managers: - [UseState](#usestate) - [UseAsyncState](#useasyncstate) - [UseReducer](#usereducer) +- [UseCompute](#usecompute) > **NOTE:** -> The hooks (also known as [`ReactterHook`](https://pub.dev/documentation/reactter/latest/core/ReactterHook-class.html)) are named with the prefix `Use` according to convention. +> The hooks (also known as [`ReactterHook`](https://pub.dev/documentation/reactter/latest/reactter/ReactterHook-class.html)) are named with the prefix `Use` according to convention. > > **RECOMMENDED:** > See also [different between Signal and UseState](#different-between-signal-and-usestate) and about [custom hooks](#custom-hooks). ### Signal -[`Signal`](https://pub.dev/documentation/reactter/latest/core/Signal-class.html) is an object (that extends [`ReactterState`](https://pub.dev/documentation/reactter/latest/core/ReactterState-mixin.html)) which has a `value` and notifies about its changes. +[`Signal`](https://pub.dev/documentation/reactter/latest/reactter/Signal-class.html) is an object (that extends [`ReactterState`](https://pub.dev/documentation/reactter/latest/reactter/ReactterState-class.html)) which has a `value` and notifies about its changes. It can be initialized using the extension `.signal`: @@ -263,14 +273,14 @@ When `value` is changed, the `Signal` will emitted the following events(learn ab > **NOTE:** > When you do any arithmetic operation between two `Signal`s, its return a `Obj`, for example: `1.signal + 2.signal` return `3.obj`. -> A [`Obj`](https://pub.dev/documentation/reactter/latest/core/Obj-class.html) is like a `Signal` without reactive functionality, but you can convert it to `Signal` using `.toSignal`. +> A [`Obj`](https://pub.dev/documentation/reactter/latest/reactter/Obj-class.html) is like a `Signal` without reactive functionality, but you can convert it to `Signal` using `.toSignal`. > **NOTE:** -> In flutter, using [`ReactterWatcher`](https://pub.dev/documentation/flutter_reactter/latest/widgets/ReactterWatcher-class.html), it's a way to keep the widgets automatically updates, accessing the value of signal reactively. +> In flutter, using [`ReactterWatcher`](https://pub.dev/documentation/flutter_reactter/latest/flutter_reactter/ReactterWatcher-class.html), it's a way to keep the widgets automatically updates, accessing the value of signal reactively. ### UseState -[`UseState`](https://pub.dev/documentation/reactter/latest/hooks/UseState-class.html) is a hook([`ReactterHook`](https://pub.dev/documentation/reactter/latest/core/ReactterHook-class.html)) that allows to declare state variables and manipulate its `value`, which in turn notifies about its changes. +[`UseState`](https://pub.dev/documentation/reactter/latest/reactter/UseState-class.html) is a hook([`ReactterHook`](https://pub.dev/documentation/reactter/latest/reactter/ReactterHook-class.html)) that allows to declare state variables and manipulate its `value`, which in turn notifies about its changes. It can be declared inside a class, like this: @@ -333,7 +343,7 @@ The decision between which one to use is yours. You can use one or both without ### UseAsyncState -[`UseAsyncState`](https://pub.dev/documentation/reactter/latest/hooks/UseAsyncState-class.html) is a hook([`ReactterHook`](https://pub.dev/documentation/reactter/latest/core/ReactterHook-class.html)) with the same feature as [`UseState`](#usestate) but provides a `asyncValue` method, which will be obtained when `resolve` method is executed. +[`UseAsyncState`](https://pub.dev/documentation/reactter/latest/reactter/UseAsyncState-class.html) is a hook([`ReactterHook`](https://pub.dev/documentation/reactter/latest/reactter/ReactterHook-class.html)) with the same feature as [`UseState`](#usestate) but provides a `asyncValue` method, which will be obtained when `resolve` method is executed. This is an translate example: @@ -347,7 +357,7 @@ class TranslateArgs { } class TranslateController { - final translateState = UseAsyncStates( + late final translateState = UseAsyncStates( null, translate ); @@ -362,7 +372,6 @@ class TranslateController { ).then((_) { print("'Hello world' translated to Spanish: '${translateState.value}'"); }); - } Future translate([TranslateArgs args]) async { @@ -393,7 +402,7 @@ When `value` is changed, the `UseAsynState` will emitted the following events(le ### UseReducer -[`UseReducer`](https://pub.dev/documentation/reactter/latest/hooks/UseReducer-class.html) is a hook([`ReactterHook`](https://pub.dev/documentation/reactter/latest/core/ReactterHook-class.html)) that manages state using reducer method. An alternative to [`UseState`](#usestate). +[`UseReducer`](https://pub.dev/documentation/reactter/latest/reactter/UseReducer-class.html) is a hook([`ReactterHook`](https://pub.dev/documentation/reactter/latest/reactter/ReactterHook-class.html)) that manages state using reducer method. An alternative to [`UseState`](#usestate). > **RECOMMENDED:** > `UseReducer` is usually preferable to `UseState` when you have complex state logic that involves multiple sub-values or when the next state depends on the previous one. @@ -444,7 +453,7 @@ class CounterController { } ``` -The actions can be created as a callable class, extending from [`ReactterActionCallable`](https://pub.dev/documentation/reactter/latest/hooks/ReactterActionCallable-class.html) and used as follows: +The actions can be created as a callable class, extending from [`ReactterActionCallable`](https://pub.dev/documentation/reactter/latest/reactter/ReactterActionCallable-class.html) and used as follows: ```dart class Store { @@ -488,9 +497,57 @@ When `value` is changed, the `UseReducer` will emitted the following events(lear - `Lifecycle.willUpdate` event is triggered before the `value` change or `update`, `refresh` methods have been invoked. - `Lifecicle.didUpdate` event is triggered after the `value` change or `update`, `refresh` methods have been invoked. +### UseCompute + +[`UseCompute`](https://pub.dev/documentation/reactter/latest/reactter/UseCompute-class.html) is a hook([`ReactterHook`](https://pub.dev/documentation/reactter/latest/reactter/ReactterHook-class.html)) that keeps listening for state dependencies changes, to return a computed value from a defined method. + +An example is shown below: + +```dart +class AppController { + final stateA = UseState(1); + final stateB = UseState(7); + late final computeState = UseCompute( + () => (stateA + stateB).clamp(10, 15), + [stateA, stateB], + ); + + AppController() { + print(computeState.value); // 10; + + // will print: 11, 15, 11 + Reactter.on( + computeState, + Lifecycle.didUpdate, + (_, __) => print(computeState.value), + ); + + stateA.value += 1; // computeState doesn't change, its value is 10 + stateB.value += 2; // computeState changes, its value is 11 + stateA.value += 4; // computeState changes, its value is 15 + stateB.value += 8; // computeState doesn't change, its value is 15 + stateA.value -= 8; // computeState doesn't change, its value is 15 + stateB.value -= 4; // computeState changes, its value is 11 + } +} +``` + +`UseCompute` has `value` property which represent the computed value. + +> **NOTE:** +> `UseCompute` notifies that its `value` has changed when the previous `value` is different from the current `value`. + +When `value` is changed, the `UseState` will emitted the following events(learn about it [here](#lifecycle-and-event-management)): + +- `Lifecycle.willUpdate` event is triggered before the `value` change or `update`, `refresh` methods have been invoked. +- `Lifecicle.didUpdate` event is triggered after the `value` change or `update`, `refresh` methods have been invoked. + +> **NOTE:** +> `UseCompute` is read-only, it's mean that its value cannot be changed, except by invoking the `UseCompute` method. + ### Custom hooks -Custom hooks are classes that extend [`ReactterHook`](https://pub.dev/documentation/reactter/latest/core/ReactterHook-class.html) that follow a special naming convention with the `use` prefix and can contain state logic, effects or any other custom code. +Custom hooks are classes that extend [`ReactterHook`](https://pub.dev/documentation/reactter/latest/reactter/ReactterHook-class.html) that follow a special naming convention with the `use` prefix and can contain state logic, effects or any other custom code. There are several advantages to using Custom Hooks: @@ -502,8 +559,9 @@ Here's the counter example: ```dart class UseCount extends ReactterHook { - int _count = 0; + final $ = ReactterHook.$register; + int _count = 0; int get value => _count; UseCount(int initial) : _count = initial; @@ -513,6 +571,10 @@ class UseCount extends ReactterHook { } ``` +> **IMPORTANT:** +> For creating a `ReactterHook`, it must be registered by adding the following line: +> `final $ = ReactterHook.$register;` +> > **NOTE:** > `ReactterHook` provides `update` method which notifies about its changed. @@ -525,17 +587,19 @@ class AppController { AppController() { Timer.periodic(Duration(seconds: 1), (_) => count.increment()); - // Tracking of changes via a useEffect - UseEffect(() { - print("UseEffect | Count: ${count.value}"); - }, [count], this); + // Print count value every second + Reactter.on( + count, + Lifecycle.didUpdate, + (_, __) => print("Count: ${count.value}", + ); } } ``` ## Dependency injection -With Reactter, you can create, delete and access the desired object from a single location([`ReactterInstanceManager`](https://pub.dev/documentation/reactter/latest/core/ReactterInstanceManager-mixin.html)), and you can do it from anywhere in the code, thanks to reactter's dependency injection system. +With Reactter, you can create, delete and access the desired object from a single location, and you can do it from anywhere in the code, thanks to reactter's dependency injection system. Dependency injection offers several benefits. It promotes the principle of inversion of control, where the control over object creation and management is delegated to Reactter. This improves code modularity, reusability, and testability.It also simplifies the code by removing the responsibility of creating dependencies from individual classes, making them more focused on their core functionality. @@ -569,7 +633,7 @@ Reactter offers several convenient shortcuts for managing instances: ```dart final appController = Reactter.get(); - final appControllerWithId = Reactter.get(id: 'uniqueId'); + final appControllerWithId = Reactter.get('uniqueId'); ``` - **`Reactter.create`**: This method registers, creates and retrieves the instance directly. @@ -586,16 +650,13 @@ Reactter offers several convenient shortcuts for managing instances: Reactter.delete('uniqueId'); ``` -> **NOTE:** -> These methods mentioned above are exposed by [`ReactterInstanceManager`](). -> > **NOTE:** > The scope of the registered instances is global. > This indicates that using `Reactter.get` or [`UseContext`](#usecontext) will allow you to access them from anywhere in the project. ### UseContext -[`UseContext`](https://pub.dev/documentation/reactter/latest/hooks/UseContext-class.html) is a hook([`ReactterHook`](https://pub.dev/documentation/reactter/latest/core/ReactterHook-class.html)) that allows to get the `T` instance with/without `id` from dependency store when it's ready. +[`UseContext`](https://pub.dev/documentation/reactter/latest/reactter/UseContext-class.html) is a hook([`ReactterHook`](https://pub.dev/documentation/reactter/latest/reactter/ReactterHook-class.html)) that allows to get the `T` instance with/without `id` from dependency store when it's ready. ```dart class AppController { @@ -621,14 +682,14 @@ Use [`UseEffect`](#useeffect) hook as shown in the example above, to wait for th ### ReactterProvider -[`ReactterProvider`](https://pub.dev/documentation/flutter_reactter/latest/widgets/ReactterProvider-class.html) is a Widget (exclusive of `flutter_reactter`) that hydrates from an `T` instance to the Widget tree. The `T` instance can be access through methods [BuildContext extension](#buildcontext-extension): +[`ReactterProvider`](https://pub.dev/documentation/flutter_reactter/latest/flutter_reactter/ReactterProvider-class.html) is a Widget (exclusive of `flutter_reactter`) that hydrates from an `T` instance to the Widget tree. The `T` instance can be access through methods [BuildContext extension](#buildcontext-extension): ```dart ReactterProvider( () => CounterController(), builder: (counterController, context, child) { context.watch(); - // `context.watch` watches any CounterController changes for rebuild + // `context.watch` listens any CounterController changes for rebuild return Text("count: ${counterController.count.value}"); }, ) @@ -637,16 +698,16 @@ ReactterProvider( Uses `id` property to identify the `T` instance. Use `child` property to pass a Widget which to be built once only. -It will be sent through the `builder` callback, so you can incorporate it into your build. +It will be sent through the `builder` method, so you can incorporate it into your build. > **RECOMMENDED:** > Dont's use Object with constructor parameters to prevent conflicts. > -> **NOTE:** `ReactteProvider` is a "scoped". So, the `builder` callback will be rebuild, when the instance changes or any `ReactterState` specified using the watch methods of [BuildContext extension](#buildcontext-extension). +> **NOTE:** `ReactteProvider` is a "scoped". So, the `builder` method will be rebuild, when the instance changes or any `ReactterState` specified using the watch methods of [BuildContext extension](#buildcontext-extension). ### ReactterProviders -[`ReactterProviders`](https://pub.dev/documentation/flutter_reactter/latest/widgets/ReactterProviders-class.html) is a Widget (exclusive of `flutter_reactter`) that allows to use multiple [`ReactterProvider`](#reactterprovider) as nested way. +[`ReactterProviders`](https://pub.dev/documentation/flutter_reactter/latest/flutter_reactter/ReactterProviders-class.html) is a Widget (exclusive of `flutter_reactter`) that allows to use multiple [`ReactterProvider`](#reactterprovider) as nested way. ```dart ReactterProviders( @@ -675,7 +736,7 @@ ReactterProviders( > **RECOMMENDED:** > Dont's use Object with constructor parameters to prevent conflicts. > -> **NOTE:** `ReactteProviders` is a "scoped". So, the `builder` callback will be rebuild, when the instance changes or any `ReactterState` specified using the watch methods of [BuildContext extension](#buildcontext-extension). +> **NOTE:** `ReactteProviders` is a "scoped". So, the `builder` method will be rebuild, when the instance changes or any `ReactterState` specified using the watch methods of [BuildContext extension](#buildcontext-extension). ### ReactterComponent @@ -714,7 +775,7 @@ Use `listenAll` getter as `true` to listen all the `T` instance changes to rebui ## LifeCycle and event management -In Reactter, the states([`ReactterState`](#state-management)) and the instances (managed by the [`dependency injection`](#dependency-injection)) contain different stages, also known as [`LifeCycle`](https://pub.dev/documentation/reactter/latest/core/Lifecycle.html). This lifecycle's linked events are as follows: +In Reactter, the states([`ReactterState`](#state-management)) and the instances (managed by the [`dependency injection`](#dependency-injection)) contain different stages, also known as [`LifeCycle`](https://pub.dev/documentation/reactter/latest/reactter/Lifecycle.html). This lifecycle's linked events are as follows: - **`Lifecycle.registered`**: This event is triggered when the instance has been registered. - **`Lifecycle.unregistered`**: This event is triggered when the instance is no longer registered. @@ -731,6 +792,7 @@ Reactter offers the following several event managers: - [Shortcuts to manage events](#shortcuts-to-manage-instances) - [UseEvent](#useevent) - [UseEffect](#useeffect) +- [ReactterConsumer](#reactterconsumer) - [ReactterWatcher](#reactterwatcher) - [BuildContext extension](#buildcontext-extension) @@ -784,9 +846,6 @@ Reactter offers several convenient shortcuts for managing events: await Reactter.emitAsync(ReactterInstance(), CustomEnum.EventName, "test param"); ``` -> **NOTE:** -> These methods mentioned above are exposed by [`ReactterEventManager`](). -> > **NOTE:** > The `ReactterInstance` helps to find the instance for event. > @@ -795,7 +854,7 @@ Reactter offers several convenient shortcuts for managing events: ### UseEvent -[`UseEvent`](https://pub.dev/documentation/reactter/latest/hooks/UseEvent-class.html) is a hook([`ReactterHook`](https://pub.dev/documentation/reactter/latest/core/ReactterHook-class.html)) that allows to manager events. +[`UseEvent`](https://pub.dev/documentation/reactter/latest/reactter/UseEvent-class.html) is a hook([`ReactterHook`](https://pub.dev/documentation/reactter/latest/reactter/ReactterHook-class.html)) that allows to manager events. Use `on` method to listen for instance's event: @@ -834,7 +893,7 @@ UseEvent().emit(Events.SomeEvent, 'Parameter'); ### UseEffect -[`UseEffect`](https://pub.dev/documentation/reactter/latest/hooks/UseEffect-class.html) is a hook([`ReactterHook`](https://pub.dev/documentation/reactter/latest/core/ReactterHook-class.html)) that allows to manager side-effect. +[`UseEffect`](https://pub.dev/documentation/reactter/latest/reactter/UseEffect-class.html) is a hook([`ReactterHook`](https://pub.dev/documentation/reactter/latest/reactter/ReactterHook-class.html)) that allows to manager side-effect. ```dart UseEffect( @@ -883,9 +942,103 @@ UseEffect( > **NOTE:** > If you don't add `instance` argument to `UseEffect`, the `callback` don't execute on lifecycle `didMount`, and the `cleanup` don't execute on lifecycle `willUnmount` (theses `LifeCycle` events are used with `flutter_reactter` only). +### ReactterConsumer + +[`ReactterConsumer`](https://pub.dev/documentation/flutter_reactter/latest/flutter_reactter/ReactterConsumer-class.html) is a Widget (exclusive of `flutter_reactter`) that allows to access the `T` instance from `ReactterProvider`'s nearest ancestor and can listen all or specified states +to rebuild the Widget when theses changes occur: + +```dart +class SomeWidget extends StatelessWidget { + ... + Widget build(context) { + return ReactterConsumer( + builder: (appController, context, child) { + // This is built once only. + return Text("My instance: $appContoller"); + } + ); + } +} +``` + +Use `listenAll` property as `true` to listen all the `T` instance changes to rebuild the Widget tree defined in `builder` method: + +```dart +class SomeWidget extends StatelessWidget { + ... + Widget build(context) { + return ReactterConsumer( + listenAll: true, + builder: (appController, context, child) { + // This is built every change that occurs. + return Text("My instance: $appContoller - ${DateTime.now()}"); + } + ); + } +} +``` + +Use `listenStates` property to define the states and with its changes rebuild the Widget tree defined in `builder` method: + +```dart +class SomeWidget extends StatelessWidget { + ... + Widget build(context) { + return ReactterConsumer( + listenStates: (inst) => [inst.stateA, inst.stateB], + builder: (appController, context, child) { + // This is built when stateA or stateB has changed. + return Column( + children: [ + Text("My instance: $appContoller"), + Text("StateA: ${appContoller.stateA.value}"), + Text("StateB: ${appContoller.stateB.value}"), + ], + ); + } + ); + } +} +``` + +> **NOTE:** You can use [`List.when`](https://pub.dev/documentation/flutter_reactter/latest/flutter_reactter/ReactterStateListExtension/when.html) extension for more specific conditional state when you want the widget tree to be re-rendered. For example: + +```dart + +class SomeWidget extends StatelessWidget { + ... + Widget build(context) { + return ReactterConsumer( + listenStates: (inst) => [inst.stateA, inst.stateB].when( + () => inst.stateA.value == inst.stateB.value, // condition + // The following condition functions as `or` like: + // condition || condition2 || condition3 + () => inst.stateA.value == 'X', // condition2 + () => inst.stateB.value == 'Y', // condition3 + ), + builder: (appController, context, child) { + // This is built according to the above conditions. + return Column( + children: [ + Text("My instance: $appContoller"), + Text("StateA: ${appContoller.stateA.value}"), + Text("StateB: ${appContoller.stateB.value}"), + ], + ); + } + ); + } +} +``` + +Uses `id` property to identify the `T` instance. + +Use `child` property to pass a Widget which to be built once only. +It will be sent through the `builder` method, so you can incorporate it into your build. + ### ReactterWatcher -[`ReactterWatcher`](https://pub.dev/documentation/flutter_reactter/latest/widgets/ReactterWatcher-class.html) is a Widget (exclusive of `flutter_reactter`) that allows to listen all `Signal`s contained in `builder` property and rebuilt the Widget when it changes: +[`ReactterWatcher`](https://pub.dev/documentation/flutter_reactter/latest/flutter_reactter/ReactterWatcher-class.html) is a Widget (exclusive of `flutter_reactter`) that allows to listen all `Signal`s contained in `builder` property and rebuilt the Widget when it changes: ```dart final count = 0.signal; @@ -931,23 +1084,38 @@ class App extends StatelessWidget { Reactter provides additional methods through `BuildContext` to access to instance. These are following: -- **`context.watch`**: Gets the `T` instance from `ReactterProvider`'s nearest ancestor and watches any instance changes or `ReactterState` changes declared in first paramater. +- **`context.watch`**: Gets the `T` instance from `ReactterProvider`'s nearest ancestor and listens any instance changes or `ReactterState` changes declared in first paramater. ```dart -// watches any `AppController` changes +// listens any `AppController` changes final appController = context.watch(); -// watches the states changes declared in first paramater. +// listens the states changes declared in first paramater. final appController = context.watch( (inst) => [inst.stateA, inst.stateB], ); ``` -- **`context.watchId`**: Gets the `T` instance by `id` from `ReactterProvider`'s nearest ancestor and watches instance changes or `ReactterState` changes declared in second paramater. +> **NOTE:** You can use [`List.when`](https://pub.dev/documentation/flutter_reactter/latest/flutter_reactter/ReactterStateListExtension/when.html) extension for more specific conditional state when you want the widget tree to be re-rendered. For example: + +```dart +final appController = context.watch( + (inst) => [inst.stateA, inst.stateB].when( + () => inst.stateA.value == inst.stateB.value, // condition + // The following condition functions as `or` like: + // condition || condition2 || condition3 + () => inst.stateA.value == 'X', // condition2 + () => inst.stateB.value == 'Y', // condition3 + ), +); +``` + + +- **`context.watchId`**: Gets the `T` instance by `id` from `ReactterProvider`'s nearest ancestor and listens instance changes or `ReactterState` changes declared in second paramater. ```dart -// watches any `ResourceController` by `id` changes +// listens any `ResourceController` by `id` changes final resourceController = context.watchId('UniqueId'); -// watches the states changes declared in second paramater. +// listens the states changes declared in second paramater. final resourceController = context.watchId( 'UniqueId', (inst) => [inst.stateA, inst.stateB], @@ -962,13 +1130,13 @@ final resourceController = context.use('UniqueId'); ``` > **NOTE:** -> These methods mentioned above uses [`ReactterProvider.contextOf`](https://pub.dev/documentation/flutter_reactter/latest/widgets/ReactterProvider/contextOf.html) +> These methods mentioned above uses [`ReactterProvider.contextOf`](https://pub.dev/documentation/flutter_reactter/latest/flutter_reactter/ReactterProvider/contextOf.html) > > **NOTE:** -> `context.watch` and `context.watchId` watch all or some of the specified [`ReactterState`](https://pub.dev/documentation/reactter/latest/core/ReactterState-mixin.html) dependencies, when any it will changes, re-built the Widgets tree in the scope of [`ReactterProvider`](#reactterprovider), [`ReactterComponent`](#reacttercomponent) or any Widget that exposes the `BuildContext` like `Build`, `StatelessWidget`, `StatefulWidget`. +> `context.watch` and `context.watchId` watch all or some of the specified [`ReactterState`](https://pub.dev/documentation/reactter/latest/reactter/ReactterState-mixin.html) dependencies, when any it will changes, re-built the Widgets tree in the scope of [`ReactterProvider`](#reactterprovider), [`ReactterComponent`](#reacttercomponent) or any Widget that exposes the `BuildContext` like `Build`, `StatelessWidget`, `StatefulWidget`. > > **NOTE:** -> A [`ReactterState`](#state-management) can be a [`Signal`](#signal) or [`ReactterHook`](https://pub.dev/documentation/reactter/latest/core/ReactterHook-class.html) (like [`UseState`](#usestate), [`UseAsynState`](#useasyncstate), [`UseReducer`](#usereducer) or another [Custom hooks](#custom-hooks)). +> A [`ReactterState`](#state-management) can be a [`Signal`](#signal) or [`ReactterHook`](https://pub.dev/documentation/reactter/latest/reactter/ReactterHook-class.html) (like [`UseState`](#usestate), [`UseAsynState`](#useasyncstate), [`UseReducer`](#usereducer) or another [Custom hooks](#custom-hooks)). ## Resources diff --git a/packages/flutter_reactter/example/pubspec.lock b/packages/flutter_reactter/example/pubspec.lock index f0b1e549..2720d996 100644 --- a/packages/flutter_reactter/example/pubspec.lock +++ b/packages/flutter_reactter/example/pubspec.lock @@ -1,6 +1,38 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + sha256: "405666cd3cf0ee0a48d21ec67e65406aad2c726d9fa58840d3375e7bdcd32a07" + url: "https://pub.dev" + source: hosted + version: "60.0.0" + analyzer: + dependency: transitive + description: + name: analyzer + sha256: "1952250bd005bacb895a01bf1b4dc00e3ba1c526cf47dca54dfe24979c65f5b3" + url: "https://pub.dev" + source: hosted + version: "5.12.0" + analyzer_plugin: + dependency: transitive + description: + name: analyzer_plugin + sha256: c1d5f167683de03d5ab6c3b53fc9aeefc5d59476e7810ba7bbddff50c6f4392d + url: "https://pub.dev" + source: hosted + version: "0.11.2" + args: + dependency: transitive + description: + name: args + sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 + url: "https://pub.dev" + source: hosted + version: "2.4.2" async: dependency: transitive description: @@ -25,6 +57,30 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.1" + checked_yaml: + dependency: transitive + description: + name: checked_yaml + sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff + url: "https://pub.dev" + source: hosted + version: "2.0.3" + ci: + dependency: transitive + description: + name: ci + sha256: "145d095ce05cddac4d797a158bc4cf3b6016d1fe63d8c3d2fbd7212590adca13" + url: "https://pub.dev" + source: hosted + version: "0.1.0" + cli_util: + dependency: transitive + description: + name: cli_util + sha256: b8db3080e59b2503ca9e7922c3df2072cf13992354d5e944074ffa836fba43b7 + url: "https://pub.dev" + source: hosted + version: "0.4.0" collection: dependency: transitive description: @@ -33,6 +89,62 @@ packages: url: "https://pub.dev" source: hosted version: "1.17.1" + convert: + dependency: transitive + description: + name: convert + sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + url: "https://pub.dev" + source: hosted + version: "3.1.1" + crypto: + dependency: transitive + description: + name: crypto + sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab + url: "https://pub.dev" + source: hosted + version: "3.0.3" + custom_lint: + dependency: transitive + description: + name: custom_lint + sha256: b09a939c3bb062fdf072aa4c8eb5447231338854c4fefb23e4c9f7cef41cb3ff + url: "https://pub.dev" + source: hosted + version: "0.5.0" + custom_lint_builder: + dependency: transitive + description: + name: custom_lint_builder + sha256: f1430048ccddcd82cbf7722fce7701530fd535b82e91f45b0c81ed07814143bf + url: "https://pub.dev" + source: hosted + version: "0.5.0" + custom_lint_core: + dependency: transitive + description: + name: custom_lint_core + sha256: a39e98cba1d96076e2e5c96aad582a776909c78b4d7480d0efdcc3791b225c1b + url: "https://pub.dev" + source: hosted + version: "0.5.0" + dart_style: + dependency: transitive + description: + name: dart_style + sha256: "1efa911ca7086affd35f463ca2fc1799584fb6aa89883cf0af8e3664d6a02d55" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + file: + dependency: transitive + description: + name: file + sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" + url: "https://pub.dev" + source: hosted + version: "6.1.4" flutter: dependency: "direct main" description: flutter @@ -50,23 +162,47 @@ packages: dependency: "direct main" description: name: flutter_reactter - sha256: "96aa88f54187d6eec019de914cc9b3fc53aafd2ca64c2af2d8d6a0a15b837260" + sha256: "6e655eef632e5c959019b1c281763c787123dd13dd3bb6b4131e502d15a325ed" url: "https://pub.dev" source: hosted - version: "5.0.0" + version: "5.1.0" flutter_web_plugins: dependency: transitive description: flutter source: sdk version: "0.0.0" + freezed_annotation: + dependency: transitive + description: + name: freezed_annotation + sha256: aeac15850ef1b38ee368d4c53ba9a847e900bb2c53a4db3f6881cbb3cb684338 + url: "https://pub.dev" + source: hosted + version: "2.2.0" + glob: + dependency: transitive + description: + name: glob + sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + hotreloader: + dependency: transitive + description: + name: hotreloader + sha256: "728c0613556c1d153f7e7f4a367cffacc3f5a677d7f6497a1c2b35add4e6dacf" + url: "https://pub.dev" + source: hosted + version: "3.0.6" http: dependency: "direct main" description: name: http - sha256: "2ed163531e071c2c6b7c659635112f24cb64ecbebf6af46b550d536c0b1aa112" + sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525" url: "https://pub.dev" source: hosted - version: "0.13.4" + version: "1.1.0" http_parser: dependency: transitive description: @@ -83,6 +219,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.6.7" + json_annotation: + dependency: transitive + description: + name: json_annotation + sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467 + url: "https://pub.dev" + source: hosted + version: "4.8.1" lints: dependency: transitive description: @@ -91,6 +235,22 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.0" + logging: + dependency: transitive + description: + name: logging + sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + matcher: + dependency: transitive + description: + name: matcher + sha256: c94db23593b89766cda57aab9ac311e3616cf87c6fa4e9749df032f66f30dcb8 + url: "https://pub.dev" + source: hosted + version: "0.12.14" material_color_utilities: dependency: transitive description: @@ -107,6 +267,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.9.1" + package_config: + dependency: transitive + description: + name: package_config + sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" + url: "https://pub.dev" + source: hosted + version: "2.1.0" path: dependency: transitive description: @@ -123,14 +291,46 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.2" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + pubspec_parse: + dependency: transitive + description: + name: pubspec_parse + sha256: c63b2876e58e194e4b0828fcb080ad0e06d051cb607a6be51a9e084f47cb9367 + url: "https://pub.dev" + source: hosted + version: "1.2.3" reactter: dependency: transitive description: name: reactter - sha256: "625497afc650373e8baa5c488df5d0b01f48b5a733f424e7f83bfa1d0638c63a" + sha256: dfb24ed31695dbea1567739c9db93a260073b8cb154b3284f930476c1a8418dc + url: "https://pub.dev" + source: hosted + version: "5.1.0" + reactter_lint: + dependency: "direct dev" + description: + name: reactter_lint + sha256: "33073d0fa0539980c103739ac66a49a6dc11849b35e6d40a1f522751cfb60e65" url: "https://pub.dev" source: hosted - version: "5.0.0" + version: "0.0.3" + rxdart: + dependency: transitive + description: + name: rxdart + sha256: "0c7c0cedd93788d996e33041ffecda924cc54389199cde4e6a34b440f50044cb" + url: "https://pub.dev" + source: hosted + version: "0.27.7" sky_engine: dependency: transitive description: flutter @@ -144,6 +344,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.8.2" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + url: "https://pub.dev" + source: hosted + version: "1.11.1" + stream_transform: + dependency: transitive + description: + name: stream_transform + sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f" + url: "https://pub.dev" + source: hosted + version: "2.1.0" string_scanner: dependency: transitive description: @@ -232,6 +448,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.1" + uuid: + dependency: transitive + description: + name: uuid + sha256: "648e103079f7c64a36dc7d39369cabb358d377078a051d6ae2ad3aa539519313" + url: "https://pub.dev" + source: hosted + version: "3.0.7" vector_math: dependency: transitive description: @@ -240,6 +464,30 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: b8c67f5fa3897b122cf60fe9ff314f7b0ef71eab25c5f8b771480bc338f48823 + url: "https://pub.dev" + source: hosted + version: "11.7.2" + watcher: + dependency: transitive + description: + name: watcher + sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + yaml: + dependency: transitive + description: + name: yaml + sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" + url: "https://pub.dev" + source: hosted + version: "3.1.2" sdks: - dart: ">=3.0.0-0 <4.0.0" + dart: ">=3.0.0 <4.0.0" flutter: ">=2.10.0" diff --git a/packages/flutter_reactter/example/pubspec.yaml b/packages/flutter_reactter/example/pubspec.yaml index b276b698..7402aa73 100644 --- a/packages/flutter_reactter/example/pubspec.yaml +++ b/packages/flutter_reactter/example/pubspec.yaml @@ -11,12 +11,13 @@ environment: dependencies: flutter: sdk: flutter - http: ^0.13.4 + http: ^1.1.0 url_launcher: ^6.1.2 - flutter_reactter: ^5.0.0 + flutter_reactter: ^5.1.0 dev_dependencies: flutter_lints: ^2.0.0 + reactter_lint: ^0.0.3 flutter: uses-material-design: true diff --git a/packages/flutter_reactter/pubspec.lock b/packages/flutter_reactter/pubspec.lock index c37a80a5..79c31f60 100644 --- a/packages/flutter_reactter/pubspec.lock +++ b/packages/flutter_reactter/pubspec.lock @@ -153,10 +153,10 @@ packages: dependency: "direct main" description: name: reactter - sha256: cf7590891ef28b7dc2e567a7e2bd7b89215cd5105fce832eb38412b65c23e97f + sha256: dfb24ed31695dbea1567739c9db93a260073b8cb154b3284f930476c1a8418dc url: "https://pub.dev" source: hosted - version: "5.0.1" + version: "5.1.0" sky_engine: dependency: transitive description: flutter diff --git a/packages/flutter_reactter/pubspec.yaml b/packages/flutter_reactter/pubspec.yaml index 44f6a761..42950c13 100644 --- a/packages/flutter_reactter/pubspec.yaml +++ b/packages/flutter_reactter/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_reactter description: A light, powerful and quick Reactive State Management, Dependency Injection and Event Management. -version: 5.0.1 +version: 5.1.0 homepage: https://2devs.io license: MIT License repository: https://github.com/2devs-team/reactter @@ -12,7 +12,7 @@ environment: dependencies: flutter: sdk: flutter - reactter: ^5.0.1 + reactter: ^5.1.0 dev_dependencies: flutter_driver: diff --git a/packages/reactter/pubspec.lock b/packages/reactter/pubspec.lock index 21a91a5e..f6d2ab6b 100644 --- a/packages/reactter/pubspec.lock +++ b/packages/reactter/pubspec.lock @@ -67,14 +67,6 @@ packages: description: flutter source: sdk version: "0.0.0" - flutter_lints: - dependency: "direct dev" - description: - name: flutter_lints - sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c - url: "https://pub.dev" - source: hosted - version: "2.0.1" flutter_test: dependency: "direct dev" description: flutter @@ -93,14 +85,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.6.7" - lints: - dependency: transitive - description: - name: lints - sha256: "6b0206b0bf4f04961fc5438198ccb3a885685cd67d4d4a32cc20ad7f8adbe015" - url: "https://pub.dev" - source: hosted - version: "2.1.0" matcher: dependency: transitive description: @@ -235,4 +219,4 @@ packages: source: hosted version: "3.0.2" sdks: - dart: ">=3.0.0-417 <4.0.0" + dart: ">=3.0.0-0 <4.0.0" diff --git a/packages/reactter/pubspec.yaml b/packages/reactter/pubspec.yaml index d6dcc1a8..2ece30df 100644 --- a/packages/reactter/pubspec.yaml +++ b/packages/reactter/pubspec.yaml @@ -1,6 +1,6 @@ name: reactter description: A light, powerful and quick Reactive State Management, Dependency Injection and Event Management. -version: 5.0.1 +version: 5.1.0 homepage: https://2devs.io license: MIT License repository: https://github.com/2devs-team/reactter @@ -14,6 +14,5 @@ dependencies: dev_dependencies: flutter_driver: sdk: flutter - flutter_lints: ^2.0.1 flutter_test: sdk: flutter