usemodel.rs 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. //! When building complex components, it's occasionally useful to dip into a pure MVC pattern instead of the
  2. //! React hooks pattern. Hooks are useful to abstract over some reusable logic, but many models are not reusable
  3. //! in the same way that hooks are.
  4. //!
  5. //! In these cases, we provide `use_model` - a convenient way of abstracting over some state and async functions.
  6. use dioxus_core::prelude::ScopeState;
  7. use std::{
  8. cell::{Cell, Ref, RefCell, RefMut},
  9. future::Future,
  10. marker::PhantomData,
  11. pin::Pin,
  12. rc::Rc,
  13. };
  14. pub fn use_model<'a, T: 'static>(cx: &'a ScopeState, f: impl FnOnce() -> T) -> UseModel<'a, T> {
  15. let inner = cx.use_hook(|_| UseModelInner {
  16. update_scheduled: Cell::new(false),
  17. update_callback: cx.schedule_update(),
  18. value: RefCell::new(f()),
  19. // tasks: RefCell::new(Vec::new()),
  20. });
  21. inner.update_scheduled.set(false);
  22. UseModel { inner }
  23. }
  24. pub struct UseModel<'a, T> {
  25. inner: &'a UseModelInner<T>,
  26. }
  27. struct UseModelInner<T> {
  28. update_scheduled: Cell<bool>,
  29. update_callback: Rc<dyn Fn()>,
  30. value: RefCell<T>,
  31. // tasks: RefCell<Vec<ModelTask>>,
  32. }
  33. type ModelTask = Pin<Box<dyn Future<Output = ()> + 'static>>;
  34. impl<'a, T: 'static> UseModel<'a, T> {
  35. pub fn read(&self) -> Ref<'_, T> {
  36. self.inner.value.borrow()
  37. }
  38. pub fn write(&self) -> RefMut<'_, T> {
  39. self.needs_update();
  40. self.inner.value.borrow_mut()
  41. }
  42. /// Allows the ability to write the value without forcing a re-render
  43. pub fn write_silent(&self) -> RefMut<'_, T> {
  44. self.inner.value.borrow_mut()
  45. }
  46. pub fn needs_update(&self) {
  47. if !self.inner.update_scheduled.get() {
  48. self.inner.update_scheduled.set(true);
  49. (self.inner.update_callback)();
  50. }
  51. }
  52. pub fn set(&self, new: T) {
  53. *self.inner.value.borrow_mut() = new;
  54. self.needs_update();
  55. }
  56. pub fn read_write(&self) -> (Ref<'_, T>, &Self) {
  57. (self.read(), self)
  58. }
  59. pub fn start(&self, _f: impl FnOnce() -> ModelTask) {
  60. todo!()
  61. }
  62. }
  63. // keep a coroutine going
  64. pub fn use_model_coroutine<'a, T, F: Future<Output = ()> + 'static>(
  65. cx: &'a ScopeState,
  66. _model: UseModel<T>,
  67. _f: impl FnOnce(AppModels) -> F,
  68. ) -> UseModelCoroutine {
  69. cx.use_hook(|_| UseModelTaskInner {
  70. task: Default::default(),
  71. });
  72. todo!()
  73. }
  74. impl<T> Copy for UseModel<'_, T> {}
  75. impl<'a, T> Clone for UseModel<'a, T> {
  76. fn clone(&self) -> Self {
  77. Self { inner: self.inner }
  78. }
  79. }