Implement effects using reactivecontext
This commit is contained in:
21 files changed
+287
-320
No files matched your search
@@ -111,6 +111,11 @@ pub fn needs_update() {
|
||||
Runtime::with_current_scope(|cx| cx.needs_update());
|
||||
}
|
||||
|
||||
/// Mark the current scope as dirty, causing it to re-render
|
||||
pub fn needs_update_any(id: ScopeId) {
|
||||
Runtime::with_current_scope(|cx| cx.needs_update_any(id));
|
||||
}
|
||||
|
||||
/// Schedule an update for the current component
|
||||
///
|
||||
/// Note: Unlike [`needs_update`], the function returned by this method will work outside of the dioxus runtime.
|
||||
@@ -252,6 +257,10 @@ pub fn after_render(f: impl FnMut() + 'static) {
|
||||
/// Effects rely on this to ensure that they only run effects after the DOM has been updated. Without flush_sync effects
|
||||
/// are run immediately before diffing the DOM, which causes all sorts of out-of-sync weirdness.
|
||||
pub async fn flush_sync() {
|
||||
// if flushing() {
|
||||
// return;
|
||||
// }
|
||||
|
||||
_ = Runtime::with(|rt| rt.flush.clone())
|
||||
.unwrap()
|
||||
.recv_async()
|
||||
|
||||
@@ -88,13 +88,13 @@ pub use crate::innerlude::{
|
||||
pub mod prelude {
|
||||
pub use crate::innerlude::{
|
||||
consume_context, consume_context_from_scope, current_scope_id, fc_to_builder, flush_sync,
|
||||
generation, has_context, needs_update, parent_scope, provide_context, provide_root_context,
|
||||
remove_future, schedule_update, schedule_update_any, spawn, spawn_forever, suspend,
|
||||
try_consume_context, use_after_render, use_before_render, use_drop, use_error_boundary,
|
||||
use_hook, use_hook_with_cleanup, AnyValue, Attribute, Component, ComponentFunction,
|
||||
Element, ErrorBoundary, Event, EventHandler, Fragment, HasAttributes, IntoAttributeValue,
|
||||
IntoDynNode, OptionStringFromMarker, Properties, Runtime, RuntimeGuard, ScopeId,
|
||||
ScopeState, SuperFrom, SuperInto, Task, Template, TemplateAttribute, TemplateNode, Throw,
|
||||
VNode, VNodeInner, VirtualDom,
|
||||
generation, has_context, needs_update, needs_update_any, parent_scope, provide_context,
|
||||
provide_root_context, remove_future, schedule_update, schedule_update_any, spawn,
|
||||
spawn_forever, suspend, try_consume_context, use_after_render, use_before_render, use_drop,
|
||||
use_error_boundary, use_hook, use_hook_with_cleanup, AnyValue, Attribute, Component,
|
||||
ComponentFunction, Element, ErrorBoundary, Event, EventHandler, Fragment, HasAttributes,
|
||||
IntoAttributeValue, IntoDynNode, OptionStringFromMarker, Properties, Runtime, RuntimeGuard,
|
||||
ScopeId, ScopeState, SuperFrom, SuperInto, Task, Template, TemplateAttribute, TemplateNode,
|
||||
Throw, VNode, VNodeInner, VirtualDom,
|
||||
};
|
||||
}
|
||||
@@ -60,8 +60,13 @@ impl Scope {
|
||||
|
||||
/// Mark this scope as dirty, and schedule a render for it.
|
||||
pub fn needs_update(&self) {
|
||||
self.needs_update_any(self.id)
|
||||
}
|
||||
|
||||
/// Mark this scope as dirty, and schedule a render for it.
|
||||
pub fn needs_update_any(&self, id: ScopeId) {
|
||||
self.sender()
|
||||
.unbounded_send(SchedulerMsg::Immediate(self.id))
|
||||
.unbounded_send(SchedulerMsg::Immediate(id))
|
||||
.expect("Scheduler to exist if scope exists");
|
||||
}
|
||||
|
||||
|
||||
@@ -372,11 +372,15 @@ impl VirtualDom {
|
||||
///
|
||||
/// Whenever the Runtime "works", it will re-render this scope
|
||||
pub fn mark_dirty(&mut self, id: ScopeId) {
|
||||
if let Some(context) = self.runtime.get_state(id) {
|
||||
let height = context.height();
|
||||
tracing::trace!("Marking scope {:?} ({}) as dirty", id, context.name);
|
||||
self.dirty_scopes.insert(DirtyScope { height, id });
|
||||
}
|
||||
let Some(scope) = self.runtime.get_state(id) else {
|
||||
return;
|
||||
};
|
||||
|
||||
tracing::trace!("Marking scope {:?} ({}) as dirty", id, scope.name);
|
||||
self.dirty_scopes.insert(DirtyScope {
|
||||
height: scope.height(),
|
||||
id,
|
||||
});
|
||||
}
|
||||
|
||||
/// Call a listener inside the VirtualDom with data from outside the VirtualDom. **The ElementId passed in must be the id of an element with a listener, not a static node or a text node.**
|
||||
@@ -422,9 +426,6 @@ impl VirtualDom {
|
||||
/// let dom = VirtualDom::new(app);
|
||||
/// ```
|
||||
pub async fn wait_for_work(&mut self) {
|
||||
// Send the flush signal to the runtime
|
||||
_ = self.flush_tx.try_send(());
|
||||
|
||||
// And then poll the futures
|
||||
self.poll_tasks().await;
|
||||
}
|
||||
@@ -432,6 +433,9 @@ impl VirtualDom {
|
||||
/// Poll futures without progressing any futures from the flush table
|
||||
async fn poll_tasks(&mut self) {
|
||||
loop {
|
||||
// Send the flush signal to the runtime, waking up tasks
|
||||
_ = self.flush_tx.try_send(());
|
||||
|
||||
// Process all events - Scopes are marked dirty, etc
|
||||
// Sometimes when wakers fire we get a slew of updates at once, so its important that we drain this completely
|
||||
self.process_events();
|
||||
|
||||
Reference in new issue
Block a user