add memo
This commit is contained in:
1 parent
717c09c4a3
commit
7f2049b647
6 files changed
+137
-4
No files matched your search
@@ -209,6 +209,12 @@ impl<T: 'static> CopyHandle<T> {
|
|||||||
self.try_write().unwrap()
|
self.try_write().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set(&self, value: T) {
|
||||||
|
self.validate().then(|| {
|
||||||
|
*self.raw.data.borrow_mut() = Some(Box::new(value));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
pub fn ptr_eq(&self, other: &Self) -> bool {
|
pub fn ptr_eq(&self, other: &Self) -> bool {
|
||||||
#[cfg(any(debug_assertions, feature = "check_generation"))]
|
#[cfg(any(debug_assertions, feature = "check_generation"))]
|
||||||
{
|
{
|
||||||
@@ -316,6 +322,17 @@ impl Owner {
|
|||||||
self.owned.borrow_mut().push(location);
|
self.owned.borrow_mut().push(location);
|
||||||
key
|
key
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates an invalid handle. This is useful for creating a handle that will be filled in later. If you use this before the value is filled in, you will get may get a panic or an out of date value.
|
||||||
|
pub fn invalid<T: 'static>(&self) -> CopyHandle<T> {
|
||||||
|
let location = self.store.claim();
|
||||||
|
CopyHandle {
|
||||||
|
raw: location,
|
||||||
|
#[cfg(any(debug_assertions, feature = "check_generation"))]
|
||||||
|
generation: location.generation.get(),
|
||||||
|
_marker: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for Owner {
|
impl Drop for Owner {
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
use core::{self, fmt::Debug};
|
||||||
|
use std::fmt::{self, Formatter};
|
||||||
|
|
||||||
use dioxus_core::prelude::*;
|
use dioxus_core::prelude::*;
|
||||||
|
|
||||||
use crate::CopyValue;
|
use crate::CopyValue;
|
||||||
@@ -19,7 +22,13 @@ pub(crate) fn get_effect_stack() -> EffectStack {
|
|||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
pub struct Effect {
|
pub struct Effect {
|
||||||
callback: CopyValue<Box<dyn FnMut()>>,
|
pub(crate) callback: CopyValue<Box<dyn FnMut()>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for Effect {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
|
f.write_fmt(format_args!("{:?}", self.callback.value))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Effect {
|
impl Effect {
|
||||||
|
|||||||
@@ -8,8 +8,9 @@ mod rt;
|
|||||||
pub use rt::*;
|
pub use rt::*;
|
||||||
mod effect;
|
mod effect;
|
||||||
pub use effect::*;
|
pub use effect::*;
|
||||||
#[macro_use]
|
|
||||||
mod impls;
|
mod impls;
|
||||||
|
mod memo;
|
||||||
|
pub use memo::*;
|
||||||
|
|
||||||
use dioxus_core::{
|
use dioxus_core::{
|
||||||
prelude::{current_scope_id, has_context, provide_context, schedule_update_any},
|
prelude::{current_scope_id, has_context, provide_context, schedule_update_any},
|
||||||
@@ -55,7 +56,7 @@ struct SignalData<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct Signal<T: 'static> {
|
pub struct Signal<T: 'static> {
|
||||||
inner: CopyValue<SignalData<T>>,
|
pub(crate) inner: CopyValue<SignalData<T>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: 'static> Signal<T> {
|
impl<T: 'static> Signal<T> {
|
||||||
@@ -115,6 +116,11 @@ impl<T: 'static> Signal<T> {
|
|||||||
let subscribers =
|
let subscribers =
|
||||||
{ std::mem::take(&mut *self.inner.read().effect_subscribers.borrow_mut()) };
|
{ std::mem::take(&mut *self.inner.read().effect_subscribers.borrow_mut()) };
|
||||||
for effect in subscribers {
|
for effect in subscribers {
|
||||||
|
log::trace!(
|
||||||
|
"Write on {:?} triggered effect {:?}",
|
||||||
|
self.inner.value,
|
||||||
|
effect
|
||||||
|
);
|
||||||
effect.try_run();
|
effect.try_run();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,7 +128,7 @@ impl<T: 'static> Signal<T> {
|
|||||||
RefMut::map(inner, |v| &mut v.value)
|
RefMut::map(inner, |v| &mut v.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set(&mut self, value: T) {
|
pub fn set(&self, value: T) {
|
||||||
*self.write() = value;
|
*self.write() = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
use dioxus_core::prelude::*;
|
||||||
|
|
||||||
|
use crate::{get_effect_stack, CopyValue, Effect, Signal, SignalData};
|
||||||
|
|
||||||
|
pub fn use_memo<R: PartialEq>(cx: &ScopeState, f: impl FnMut() -> R + 'static) -> Signal<R> {
|
||||||
|
*cx.use_hook(|| memo(f))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn memo<R: PartialEq>(mut f: impl FnMut() -> R + 'static) -> Signal<R> {
|
||||||
|
let state = Signal::<R> {
|
||||||
|
inner: CopyValue::invalid(),
|
||||||
|
};
|
||||||
|
let effect = Effect {
|
||||||
|
callback: CopyValue::invalid(),
|
||||||
|
};
|
||||||
|
|
||||||
|
{
|
||||||
|
get_effect_stack().effects.write().push(effect);
|
||||||
|
}
|
||||||
|
state.inner.value.set(SignalData {
|
||||||
|
subscribers: Default::default(),
|
||||||
|
effect_subscribers: Default::default(),
|
||||||
|
update_any: schedule_update_any().expect("in a virtual dom"),
|
||||||
|
value: f(),
|
||||||
|
});
|
||||||
|
{
|
||||||
|
get_effect_stack().effects.write().pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
effect.callback.value.set(Box::new(move || {
|
||||||
|
let value = f();
|
||||||
|
let changed = {
|
||||||
|
let state = state.read();
|
||||||
|
value != *state
|
||||||
|
};
|
||||||
|
if changed {
|
||||||
|
state.set(value)
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
state
|
||||||
|
}
|
||||||
@@ -64,6 +64,15 @@ impl<T: 'static> CopyValue<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn invalid() -> Self {
|
||||||
|
let owner = current_owner();
|
||||||
|
|
||||||
|
Self {
|
||||||
|
value: owner.invalid(),
|
||||||
|
origin_scope: current_scope_id().expect("in a virtual dom"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn origin_scope(&self) -> ScopeId {
|
pub fn origin_scope(&self) -> ScopeId {
|
||||||
self.origin_scope
|
self.origin_scope
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
#![allow(unused, non_upper_case_globals, non_snake_case)]
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
use dioxus::prelude::*;
|
||||||
|
use dioxus_core::ElementId;
|
||||||
|
use dioxus_signals::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn memos_rerun() {
|
||||||
|
simple_logger::SimpleLogger::new().init().unwrap();
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct RunCounter {
|
||||||
|
component: usize,
|
||||||
|
effect: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
let counter = Rc::new(RefCell::new(RunCounter::default()));
|
||||||
|
let mut dom = VirtualDom::new_with_props(
|
||||||
|
|cx| {
|
||||||
|
let counter = cx.props;
|
||||||
|
counter.borrow_mut().component += 1;
|
||||||
|
|
||||||
|
let mut signal = use_signal(cx, || 0);
|
||||||
|
let memo = cx.use_hook(move || {
|
||||||
|
to_owned![counter];
|
||||||
|
memo(move || {
|
||||||
|
counter.borrow_mut().effect += 1;
|
||||||
|
println!("Signal: {:?}", signal);
|
||||||
|
signal.value()
|
||||||
|
})
|
||||||
|
});
|
||||||
|
assert_eq!(memo.value(), 0);
|
||||||
|
signal += 1;
|
||||||
|
assert_eq!(memo.value(), 1);
|
||||||
|
|
||||||
|
render! {
|
||||||
|
div {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
counter.clone(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let _ = dom.rebuild().santize();
|
||||||
|
|
||||||
|
let current_counter = counter.borrow();
|
||||||
|
assert_eq!(current_counter.component, 1);
|
||||||
|
assert_eq!(current_counter.effect, 2);
|
||||||
|
}
|
||||||
Reference in new issue
Block a user