How to create a effective Shared State that retriggers Widget building? #2244
Replies: 5 comments 40 replies
-
Hi you are welcome! Firstly, this may be possibly related: https://cjycode.com/posts/rust-ui-flutter/. Does the demo there help? Secondly, also cc @patmuk who has tried more complex state-related design patterns. |
Beta Was this translation helpful? Give feedback.
-
Thanks for your answer! I tried to use the pattern described in the block post, though it seams that i hold it wrong or dont fully understand whats going behind the scenes here. when for example having this rust snippet; #[frb(ui_mutation)]
pub fn increment(&mut self) {
self.count += 1;
} i have the problem that this argument takes a Though as i mention i plan to have a global shared reference and inner mutable state proteced by Arc<RwLocks<> or your AutoOpaque impls. For me it would be ok if i can write something like #[frb(ui_mutation)]
pub fn setItem(&self, Item: item) {
self.item.write_blocking().push(item)
}
pub fn getInnerState(&self) -> Item {
self.item.clone()
} and every-time i call increment() / setItem() i would get notified everywhere i am using getInnerState() such that a Widget would automatically be rebuild. That doesn't seam the case with what is currently generated by ui_mutation or most likely i am holding it wrong! what i am currently doing in the dart site of things is creating a Wrapper class that i call from withing dart. That would help me with dart to dart calls but not with rust to dart calls. What i am doing looks roughly like this class ItemModel with ChangeNotifier {
final MyState state;
ItemModel({required this.state});
void setItem(Item item) {
state.setItem(item: item );
notifyListeners();
}
}
and then on my Widget that i want to use it using ListenableBuilders. That way at least from dart calls i get updates. Though i thought with the frb ui_state some similar code is autogenerated, so i don't need to write it manually? Another point is if i am now changing the inner State from withing rust itself i dont go through the ItemModel class and subsequently doesn't get notified. For the one place i am needing it i am using a StreamSink currently as i outlined in the beginning. Every tip on how to structure my code better so i can mutate state from rust and dart at the same time and update it when i read it in dart would be appreciated ! |
Beta Was this translation helpful? Give feedback.
-
Hi @fzyzcjy, (and hi @Vollbrecht) I wonder if one can avoid .clone() when communicating state changes between Rust and Dart. I could not get your approach (frb_ui annotations) working and did not understood it from the code examples - but I assume that it misses thread safety yet and I saw that the state instance is created in the Dart side. Looking forward to your write-up and help improving it! I create the state singleton in the Rust side - as Rust->Dart is zero-copy, the other way around not. As the business logic is in Rust, I think it is better to have the state singleton "living" there. However, my "problem" is the following: I will handle photos and videos, so .clone()-ing them will be a performance issue. But most probably the solution will be "keep the app state small and use references for the payload" :) And, most of all, if But let me start with describing my approach:
The Problem:
So, probably Locks cannot be translated to Dart in a working way? But then again, isn't Many thanks for reading so far, and please excuse my walll-of-text. I hope it was understandable. |
Beta Was this translation helpful? Give feedback.
-
@fzyzcjy and @Vollbrecht , On the rust side there is only
and the Heavy content:
On the dart side, in
to handle UI updates. The initialization with
is important as well (although one could do it on the rust side only, using In my design only Here the important parts are the initializations:
and the rust function calls
There are just this questions open:
|
Beta Was this translation helpful? Give feedback.
-
@patmuk thanks for keeping the topic alive. Today i got also back a bit onto the topic. I inspected the ui_state and ui_mutation attributes and i now think i understand whats the trick there was. Basically they RustState you create will get a inner RustStateBase attached to it. This RustStateBase carry's a async Stream of type () with it. This Stream will be used to trigger rebuilds of the ui, by registering itself in a top most StatefullWidget. From the dart site of things you then can just use the rust state directly and it will internally using the inner onMutate method by calling add on the Stream of type (). If i understand correctly if you want to trigger now a rebuild of the ui state that you change from with in your rust code, you would have to manually call the onMutate on the RustStateBase. That would certainly work for a simple App, though overall it completely sitesteps the intelligent rebuilding of flutter if i understand correctly because it re-triggers a full rebuild on every state change? Maybe that is not a problem its just a observation. In the coming days i will go deeper here into the topics and also report back on how i will handle it in my case. @patmuk with your approach you still got me a lot to think about, thanks for that. |
Beta Was this translation helpful? Give feedback.
-
Hi and thank you for your great tool.
I played around with a couple of options to archive the above but i am still struggling on the Dart site of things. First here is roughly what i want to archive and how what i tried to archive that.
My rust code would look roughly like.
The simplest and most ergonomic way for me currently, in the case of the rust async task to also use a StreamSink parallel to the shared ref. Though i don't actually are using the StreamSink data, its only a hack to inform dart about updates so it rebuild widget state.
Now to the dart site where i am struggling currently most. I tried different approaches like writing custom ChangeNotifier classes or setState calls with lots of wrapper classes. My goal is still -> update a widget that had read the state through a shared ref it was build to retrigger when another dart widget changes. And if i could i want to avoid writing 200-300 lines of state wrappers in dart.
So i tried to readup on helpers that are provided by the bridge but i don't seam to fully grasp them. First i tried to use the #[frb(ui_state)] and using #[frb(ui_mutate)] on methods that would modify the state. Though that did not work out for me, because if a method that is annotated with ui_mutate is just a &self than it seams to not doing anything. And i cant mark it as &mut self, because at the same time lots of other places are holding a &self like the long running async task. In my testing it doesn't chrash but it just blocks the ui blockingly forever on that calls.
The generated code annotated with ui_state seams to provide something that it will autogenerate ui_notifiers for me. If that work's that would be really helpful though not sure if that is working only on
&self
The only other way currently for dart to dart updates with a rust state is using callbacks, Though that seams also to not scale well, e.g if 5 widgets are reading state A, than i need 5 callbacks collected to notify them about changes.
I am totally open to scratch what i am doing if someone has a better idea how i should structure my app here.
Beta Was this translation helpful? Give feedback.
All reactions