wip: use_reducer
@@ -117,3 +117,97 @@ mod use_ref_def {
ctx.use_hook(|| UseRef::new(initial_state_fn()), |state| &*state, |_| {})
}
}
+
+mod use_reducer_def {
+ use crate::innerlude::*;
+ use std::{cell::RefCell, ops::DerefMut, rc::Rc};
+
+ struct UseReducer<T: 'static, R: 'static> {
+ new_val: Rc<RefCell<Option<T>>>,
+ current_val: T,
+ caller: Box<dyn Fn(R) + 'static>,
+ }
+
+ /// Store state between component renders!
+ /// When called, this hook retrives a stored value and provides a setter to update that value.
+ /// When the setter is called, the component is re-ran with the new value.
+ ///
+ /// This is behaves almost exactly the same way as React's "use_state".
+ ///
+ pub fn use_reducer<'a, 'c, State: 'static, Action: 'static>(
+ ctx: &'c Context<'a>,
+ initial_state_fn: impl FnOnce() -> State,
+ reducer: impl Fn(&mut State, Action),
+ ) -> (&'a State, &'a impl Fn(Action)) {
+ ctx.use_hook(
+ move || UseReducer {
+ new_val: Rc::new(RefCell::new(None)),
+ current_val: initial_state_fn(),
+ caller: Box::new(|_| println!("setter called!")),
+ },
+ move |hook| {
+ let inner = hook.new_val.clone();
+ let scheduled_update = ctx.schedule_update();
+
+ // get ownership of the new val and replace the current with the new
+ // -> as_ref -> borrow_mut -> deref_mut -> take
+ // -> rc -> &RefCell -> RefMut -> &Option<T> -> T
+ if let Some(new_val) = hook.new_val.as_ref().borrow_mut().deref_mut().take() {
+ hook.current_val = new_val;
+ }
+
+ // todo: swap out the caller with a subscription call and an internal update
+ hook.caller = Box::new(move |new_val| {
+ // update the setter with the new value
+ // let mut new_inner = inner.as_ref().borrow_mut();
+ // *new_inner = Some(new_val);
+
+ // Ensure the component gets updated
+ scheduled_update();
+ });
+
+ // box gets derefed into a ref which is then taken as ref with the hook
+ (&hook.current_val, &hook.caller)
+ },
+ |_| {},
+ )
+ }
+
+ // #[cfg(test)]
+ mod tests {
+ use super::*;
+ use crate::prelude::*;
+ use bumpalo::Bump;
+
+ enum Actions {
+ Incr,
+ Decr,
+ }
+
+ #[allow(unused)]
+ static Example: FC<()> = |ctx, props| {
+ let (count, reduce) = use_reducer(
+ &ctx,
+ || 0,
+ |count, action| match action {
+ Actions::Incr => *count += 1,
+ Actions::Decr => *count -= 1,
+ },
+ );
+
+ ctx.render(rsx! {
+ div {
+ h1 {"Count: {count}"}
+ button {
+ "Increment"
+ onclick: move |_| reduce(Actions::Incr)
+ }
+ button {
+ "Decrement"
+ onclick: move |_| reduce(Actions::Decr)
+ }
+ }
+ })
+ };
+ }
+}
