router.rs 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. use dioxus::prelude::*;
  2. use std::{cell::RefCell, str::FromStr};
  3. use crate::{prelude::Outlet, routable::Routable, router_cfg::RouterConfig};
  4. /// The config for [`Router`].
  5. pub struct RouterConfigFactory<R: Routable> {
  6. #[allow(clippy::type_complexity)]
  7. config: RefCell<Option<Box<dyn FnOnce() -> RouterConfig<R>>>>,
  8. }
  9. #[cfg(feature = "serde")]
  10. impl<R: Routable> Default for RouterConfigFactory<R>
  11. where
  12. <R as FromStr>::Err: std::fmt::Display,
  13. R: serde::Serialize + serde::de::DeserializeOwned,
  14. {
  15. fn default() -> Self {
  16. Self::from(RouterConfig::default)
  17. }
  18. }
  19. #[cfg(not(feature = "serde"))]
  20. impl<R: Routable> Default for RouterConfigFactory<R>
  21. where
  22. <R as FromStr>::Err: std::fmt::Display,
  23. {
  24. fn default() -> Self {
  25. Self::from(RouterConfig::default)
  26. }
  27. }
  28. impl<R: Routable, F: FnOnce() -> RouterConfig<R> + 'static> From<F> for RouterConfigFactory<R> {
  29. fn from(value: F) -> Self {
  30. Self {
  31. config: RefCell::new(Some(Box::new(value))),
  32. }
  33. }
  34. }
  35. #[cfg(feature = "serde")]
  36. /// The props for [`Router`].
  37. #[derive(Props)]
  38. pub struct RouterProps<R: Routable>
  39. where
  40. <R as FromStr>::Err: std::fmt::Display,
  41. R: serde::Serialize + serde::de::DeserializeOwned,
  42. {
  43. #[props(default, into)]
  44. config: RouterConfigFactory<R>,
  45. }
  46. #[cfg(not(feature = "serde"))]
  47. /// The props for [`Router`].
  48. #[derive(Props)]
  49. pub struct RouterProps<R: Routable>
  50. where
  51. <R as FromStr>::Err: std::fmt::Display,
  52. {
  53. #[props(default, into)]
  54. config: RouterConfigFactory<R>,
  55. }
  56. #[cfg(not(feature = "serde"))]
  57. impl<R: Routable> Default for RouterProps<R>
  58. where
  59. <R as FromStr>::Err: std::fmt::Display,
  60. {
  61. fn default() -> Self {
  62. Self {
  63. config: RouterConfigFactory::default(),
  64. }
  65. }
  66. }
  67. #[cfg(feature = "serde")]
  68. impl<R: Routable> Default for RouterProps<R>
  69. where
  70. <R as FromStr>::Err: std::fmt::Display,
  71. R: serde::Serialize + serde::de::DeserializeOwned,
  72. {
  73. fn default() -> Self {
  74. Self {
  75. config: RouterConfigFactory::default(),
  76. }
  77. }
  78. }
  79. #[cfg(not(feature = "serde"))]
  80. impl<R: Routable> PartialEq for RouterProps<R>
  81. where
  82. <R as FromStr>::Err: std::fmt::Display,
  83. {
  84. fn eq(&self, _: &Self) -> bool {
  85. // prevent the router from re-rendering when the initial url or config changes
  86. true
  87. }
  88. }
  89. #[cfg(feature = "serde")]
  90. impl<R: Routable> PartialEq for RouterProps<R>
  91. where
  92. <R as FromStr>::Err: std::fmt::Display,
  93. R: serde::Serialize + serde::de::DeserializeOwned,
  94. {
  95. fn eq(&self, _: &Self) -> bool {
  96. // prevent the router from re-rendering when the initial url or config changes
  97. true
  98. }
  99. }
  100. #[cfg(not(feature = "serde"))]
  101. /// A component that renders the current route.
  102. pub fn Router<R: Routable + Clone>(cx: Scope<RouterProps<R>>) -> Element
  103. where
  104. <R as FromStr>::Err: std::fmt::Display,
  105. {
  106. use crate::prelude::{outlet::OutletContext, RouterContext};
  107. use_context_provider(cx, || {
  108. RouterContext::new(
  109. (cx.props
  110. .config
  111. .config
  112. .take()
  113. .expect("use_context_provider ran twice"))(),
  114. cx.schedule_update_any(),
  115. )
  116. });
  117. use_context_provider(cx, || OutletContext::<R> {
  118. current_level: 0,
  119. _marker: std::marker::PhantomData,
  120. });
  121. render! {
  122. Outlet::<R> {}
  123. }
  124. }
  125. #[cfg(feature = "serde")]
  126. /// A component that renders the current route.
  127. pub fn Router<R: Routable + Clone>(cx: Scope<RouterProps<R>>) -> Element
  128. where
  129. <R as FromStr>::Err: std::fmt::Display,
  130. R: serde::Serialize + serde::de::DeserializeOwned,
  131. {
  132. use_context_provider(cx, || {
  133. RouterContext::new(
  134. (cx.props
  135. .config
  136. .config
  137. .take()
  138. .expect("use_context_provider ran twice"))(),
  139. cx.schedule_update_any(),
  140. )
  141. });
  142. use_context_provider(cx, || OutletContext::<R> {
  143. current_level: 0,
  144. _marker: std::marker::PhantomData,
  145. });
  146. render! {
  147. Outlet::<R> {}
  148. }
  149. }