usemodel.rs 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  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 futures::Future;
  8. use std::{
  9. cell::{Cell, Ref, RefCell, RefMut},
  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. cx.use_hook(
  16. |_| UseModelInner {
  17. update_scheduled: Cell::new(false),
  18. update_callback: cx.schedule_update(),
  19. value: RefCell::new(f()),
  20. // tasks: RefCell::new(Vec::new()),
  21. },
  22. |inner| {
  23. inner.update_scheduled.set(false);
  24. UseModel { inner }
  25. },
  26. )
  27. }
  28. pub struct UseModel<'a, T> {
  29. inner: &'a UseModelInner<T>,
  30. }
  31. struct UseModelInner<T> {
  32. update_scheduled: Cell<bool>,
  33. update_callback: Rc<dyn Fn()>,
  34. value: RefCell<T>,
  35. // tasks: RefCell<Vec<ModelTask>>,
  36. }
  37. type ModelTask = Pin<Box<dyn Future<Output = ()> + 'static>>;
  38. impl<'a, T: 'static> UseModel<'a, T> {
  39. pub fn read(&self) -> Ref<'_, T> {
  40. self.inner.value.borrow()
  41. }
  42. pub fn write(&self) -> RefMut<'_, T> {
  43. self.needs_update();
  44. self.inner.value.borrow_mut()
  45. }
  46. /// Allows the ability to write the value without forcing a re-render
  47. pub fn write_silent(&self) -> RefMut<'_, T> {
  48. self.inner.value.borrow_mut()
  49. }
  50. pub fn needs_update(&self) {
  51. if !self.inner.update_scheduled.get() {
  52. self.inner.update_scheduled.set(true);
  53. (self.inner.update_callback)();
  54. }
  55. }
  56. pub fn set(&self, new: T) {
  57. *self.inner.value.borrow_mut() = new;
  58. self.needs_update();
  59. }
  60. pub fn read_write(&self) -> (Ref<'_, T>, &Self) {
  61. (self.read(), self)
  62. }
  63. pub fn start(&self, _f: impl FnOnce() -> ModelTask) {
  64. todo!()
  65. }
  66. }
  67. // keep a coroutine going
  68. pub fn use_model_coroutine<'a, T, F: Future<Output = ()> + 'static>(
  69. cx: &'a ScopeState,
  70. _model: UseModel<T>,
  71. _f: impl FnOnce(AppModels) -> F,
  72. ) -> UseModelCoroutine {
  73. cx.use_hook(
  74. |_| {
  75. //
  76. UseModelTaskInner {
  77. task: Default::default(),
  78. }
  79. },
  80. |inner| {
  81. if let Some(task) = inner.task.get_mut() {
  82. cx.push_task(|| task);
  83. }
  84. //
  85. todo!()
  86. },
  87. )
  88. }
  89. pub struct UseModelCoroutine {}
  90. struct UseModelTaskInner {
  91. task: RefCell<Option<ModelTask>>,
  92. }
  93. impl UseModelCoroutine {
  94. pub fn start(&self) {}
  95. }
  96. pub struct ModelAsync<T> {
  97. _p: PhantomData<T>,
  98. }
  99. impl<T> ModelAsync<T> {
  100. pub fn write(&self) -> RefMut<'_, T> {
  101. todo!()
  102. }
  103. pub fn read(&self) -> Ref<'_, T> {
  104. todo!()
  105. }
  106. }
  107. pub struct AppModels {}
  108. impl AppModels {
  109. pub fn get<T: 'static>(&self) -> ModelAsync<T> {
  110. unimplemented!()
  111. }
  112. }
  113. impl<T> Copy for UseModel<'_, T> {}
  114. impl<'a, T> Clone for UseModel<'a, T> {
  115. fn clone(&self) -> Self {
  116. Self { inner: self.inner }
  117. }
  118. }