Understanding ReArch Fundamentals #169
Replies: 3 comments 4 replies
-
Hi, and thanks for such a thoughtful discussion post! I might pin it, because I think it covers a very large amount of ground pretty concisely... I'll try to address what I can here quickly, but can go into more depth if you'd like clarification/have any questions.
No worries, all your bullet points mentioned here are effectively addressed via @rearchWidget
Widget myWidget(WidgetHandle use) { // you can also have a BuildContext or some other widget constructor params here
final count = use.data(0); // or the older use.state, if you prefer
return TextButton(
onPressed: () => count.value++,
child: Text(count.value.toString()),
):
} But that relies upon Dart macros to generate the underlying
Also no worries here, this is exactly how traditional capsules operate. (Except capsules have some optimizations that allow them to be disposed when idempotent, to free up unused memory; but rest assured any stateful capsules will not be disposed on you!) The cool part is that capsules and widgets both use the same "side effects" API, so the
Both of these use cases seem about the same, so I'm grouping them together. That is done via scoping state. Again, the macros I have in #89 will make this a lot less tedious boilerplate-wise. Your Example ApplicationI'll gladly take a look at your example app at some point, but it may take awhile for me to get around to it. Currently working on some other things at the moment...see the
They are created via
The easiest way to think of this is that no state is disposed. I.e., if you read a capsule, the widget is removed, and you read the capsule again when the widget is added back in (assuming the capsule's state wasn't update via some external means), you'll get the same value by reading that capsule. This gets a little complicated to answer more thoroughly because the true technical answer relies on capsule idempotence (a capsule is idempotent if it does not register any side effects). While what I said above is true, the ReArch implementation makes some smart optimizations that will remove idempotent capsules from memory if it can safely do so. Thus, you get the benefits of auto disposal/preventing memory leaks, but with the mental model that a capsule's state will always be intact and correct. If you want to learn more about this process, I'd recommend taking a look at my Master's Thesis. Specifically, Sections 3.3-3.3.4 for some background info, followed by Section 3.3.6. There is a bit of technical jargon there so feel free to add a comment here on anything that doesn't click at first.
Capsules are "global," so they share the same instance of the capsule. Accordingly, they will both get state updates of that same capsule. For local/ephemeral state, instead use the side effects provided on the
I'll take a look and get back to you. RearchBootstrapper is meant to bootstrap the app with a global |
Beta Was this translation helpful? Give feedback.
-
Taking a look at your example now. return _ScopedCount(
// How to fix `_TypeError (type '_WidgetHandleImpl' is not a subtype of
// type 'CapsuleHandle' in type cast)` here, `use` is `WidgetHandle`
// but `CapsuleHandle` is expected.
// Placing a cast here for compilation
scopedZoneCountManager(use as CapsuleHandle),
child: child,
);
// `app.dart`
// RearchZone(
// child: Column(
// children:[
// RearchZone(
// capsules: [myCapsule],
// child: Counter(), // This one will use the capsule in the inner `RearchZone`.
// ),
// Counter(), // This one will create a new capsule on the outer `RearchZone`
// ],
// )
// ), You could likely just use a final (count, setCount) = use.data(0);
return (
count: count,
incrementCount: () => setCount(count() + 1),
); While you can use final count = use.data(0);
return (count.value, () => count.value++); class LocalState extends RearchConsumer {
const LocalState({super.key});
@override
Widget build(BuildContext context, WidgetHandle use) {
// Can we replace the following code with a capsule (or factory) that
// creates a new state for each new widget instance?
final (:count, :incrementCount) = (() {
// Using a IIFE to encapsulate the state and actions.
// If possible use a capsule to allow reuse and encapsulation across
// multiple widgets.
final (count, setCount) = use.data(0);
return (
count: count,
incrementCount: () => setCount(count() + 1),
);
})(); Each instance of LocalState above will have its own independent state. If you mean you want to re-use that exact same counter logic across different extension Counter on SideEffectRegistrar {
(int, void Function()) count() {
final count = use.data(0);
return (count.value, () => count.value++);
}
}
// In your widgets/capsules you are now free to do a final (count, incrementCount) = use.count(); Alas, just looking at your example above, I really wish dart had proper expression support. Having to make a closure just to immediately invoke it just to avoid scope creep is really annoying. // Feedback & Questions:
//
// 1. This capsule is not being disposed when `ShareMultipleStatePage` widget is
// removed from the widget tree. Is this a bug or by design? If by design, how
// can we autoDispose the capsule when the widget is removed from the widget tree?
CountManager scopedWidgetsCountManager(CapsuleHandle use) { That's intentional; I know you wrote this example before I left another comment yesterday, but hopefully that comment should clear this up. I didn't look into every line because that'd take a bit longer but I hope I addressed all your concerns. |
Beta Was this translation helpful? Give feedback.
-
I think a video providing a tutorial or tutorial series showing how to use Rearch in a real app, maybe with clean architecture and domain driven design, would really help drive understanding and adoption of Rearch. For example, I am very keen to use it but there are no tutorials on it that a dummy like me can follow, as contrasted with what I can find for Riverpod. |
Beta Was this translation helpful? Give feedback.
-
Firstly, I wanted to acknowledge the excellent work on
Rearch
! It's impressive howRearch
approaches state management differently.Keep up the fantastic work, and thanks for encouraging developers to think in a different way about this topic. Looking forward to a macro-based implementation to simplify the development.
As a flutter developer, I normally want the following scenarios solved by a state management library:
a) Create local state for each new widget instance (Ephemeral/Local state).
FooWidget
should have its own state that is not shared with anotherFooWidget
instance in the widget tree.b) Share state globally across multiple widgets in the widget tree (App/Global State).
FooWidget
should have its state shared with anotherBarWidget
instance in the widget tree.c) Share state scoped to a "zone".
d) Share state scoped to a specific set of widgets in the widget tree.
FooWidget
could have this state shared with anotherBarWidget
instance.Given these scenarios I created a simple example project to try to solve these using
Rearch
.Repository: Rearch Example
Disclaimer: This example project was written without ever touching Rearch. It's for learning purposes, and there are definitely some bad implementations here. I am seeking feedback and answers to some questions I have about it. These are mainly written in comments.
I understand that reviewing a project can be time-consuming, so I've prepared a set of TLDR (Too Long; Didn't Read) questions while writing this. I'd appreciate it if somebody could spare a moment to address any of them.
Understanding Rearch architecture by asking practical questions:
use
in aRearchConsumer
? Are they stored onRearchBootstrapper
container?RearchConsumer
is removed from the widget tree and added again, is the capsule disposed and recreated (if is the onlyuse
ing it)? Or is the capsule cached and reused? In other words, how is managed a capsule lifecycle?RearchConsumer
use the same capsule, are they sharing the same instance or is a new instance created for each widget?RearchZone
/RearchScope
widget that replaces theRearchBootstrapper
? Checkscoped_zone_state.dart
.Beta Was this translation helpful? Give feedback.
All reactions