use_route.rs 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. use dioxus_core::{ScopeId, ScopeState};
  2. use gloo::history::{HistoryResult, Location};
  3. use serde::de::DeserializeOwned;
  4. use std::{rc::Rc, str::FromStr};
  5. use crate::RouterService;
  6. /// This struct provides is a wrapper around the internal router
  7. /// implementation, with methods for getting information about the current
  8. /// route.
  9. pub struct UseRoute {
  10. router: Rc<RouterService>,
  11. }
  12. impl UseRoute {
  13. /// This method simply calls the [`Location::query`] method.
  14. pub fn query<T>(&self) -> HistoryResult<T>
  15. where
  16. T: DeserializeOwned,
  17. {
  18. self.current_location().query::<T>()
  19. }
  20. /// Returns the nth segment in the path. Paths that end with a slash have
  21. /// the slash removed before determining the segments. If the path has
  22. /// fewer segments than `n` then this method returns `None`.
  23. pub fn nth_segment(&self, n: usize) -> Option<String> {
  24. let mut segments = self.path_segments();
  25. let len = segments.len();
  26. if len - 1 < n {
  27. return None;
  28. }
  29. Some(segments.remove(n))
  30. }
  31. /// Returns the last segment in the path. Paths that end with a slash have
  32. /// the slash removed before determining the segments. The root path, `/`,
  33. /// will return an empty string.
  34. pub fn last_segment(&self) -> String {
  35. let mut segments = self.path_segments();
  36. segments.remove(segments.len() - 1)
  37. }
  38. /// Get the named parameter from the path, as defined in your router. The
  39. /// value will be parsed into the type specified by `T` by calling
  40. /// `value.parse::<T>()`. This method returns `None` if the named
  41. /// parameter does not exist in the current path.
  42. pub fn segment<T>(&self, name: &str) -> Option<Result<T, T::Err>>
  43. where
  44. T: FromStr,
  45. {
  46. self.router
  47. .current_path_params()
  48. .get(name)
  49. .and_then(|v| Some(v.parse::<T>()))
  50. }
  51. /// Returns the [Location] for the current route.
  52. pub fn current_location(&self) -> Location {
  53. self.router.current_location()
  54. }
  55. fn path_segments(&self) -> Vec<String> {
  56. let location = self.router.current_location();
  57. let path = location.path();
  58. if path == "/" {
  59. return vec![String::new()];
  60. }
  61. let stripped = &location.path()[1..];
  62. stripped.split('/').map(str::to_string).collect::<Vec<_>>()
  63. }
  64. }
  65. /// This hook provides access to information about the current location in the
  66. /// context of a [`Router`]. If this function is called outside of a `Router`
  67. /// component it will panic.
  68. pub fn use_route(cx: &ScopeState) -> &UseRoute {
  69. &cx.use_hook(|_| {
  70. let router = cx
  71. .consume_context::<RouterService>()
  72. .expect("Cannot call use_route outside the scope of a Router component");
  73. router.subscribe_onchange(cx.scope_id());
  74. UseRouteInner {
  75. router: UseRoute { router },
  76. scope: cx.scope_id(),
  77. }
  78. })
  79. .router
  80. }
  81. struct UseRouteInner {
  82. router: UseRoute,
  83. scope: ScopeId,
  84. }
  85. impl Drop for UseRouteInner {
  86. fn drop(&mut self) {
  87. self.router.router.unsubscribe_onchange(self.scope)
  88. }
  89. }