query_segment_search.rs 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. //! This example shows how to access and use query segments present in an url on the web.
  2. //!
  3. //! The enum router makes it easy to use your route as state in your app. This example shows how to use the router to encode search text into the url and decode it back into a string.
  4. //!
  5. //! Run this example on desktop with
  6. //! ```sh
  7. //! dx serve --example query_segment_search
  8. //! ```
  9. //! Or on web with
  10. //! ```sh
  11. //! dx serve --platform web --features web --example query_segment_search -- --no-default-features
  12. //! ```
  13. use dioxus::prelude::*;
  14. fn main() {
  15. dioxus::launch(|| {
  16. rsx! {
  17. Router::<Route> {}
  18. }
  19. });
  20. }
  21. #[derive(Routable, Clone, Debug, PartialEq)]
  22. #[rustfmt::skip]
  23. enum Route {
  24. #[route("/")]
  25. Home {},
  26. // The each query segment must implement <https://docs.rs/dioxus-router/latest/dioxus_router/routable/trait.FromQueryArgument.html> and Display.
  27. // You can use multiple query segments separated by `&`s.
  28. #[route("/search?:query&:word_count")]
  29. Search {
  30. query: String,
  31. word_count: usize,
  32. },
  33. }
  34. #[component]
  35. fn Home() -> Element {
  36. // Display a list of example searches in the home page
  37. rsx! {
  38. ul {
  39. li {
  40. Link {
  41. to: Route::Search {
  42. query: "hello".to_string(),
  43. word_count: 1
  44. },
  45. "Search for results containing 'hello' and at least one word"
  46. }
  47. }
  48. li {
  49. Link {
  50. to: Route::Search {
  51. query: "dioxus".to_string(),
  52. word_count: 2
  53. },
  54. "Search for results containing 'dioxus' and at least two word"
  55. }
  56. }
  57. }
  58. }
  59. }
  60. // Instead of accepting String and usize directly, we use ReadOnlySignal to make the parameters `Copy` and let us subscribe to them automatically inside the meme
  61. #[component]
  62. fn Search(query: ReadOnlySignal<String>, word_count: ReadOnlySignal<usize>) -> Element {
  63. const ITEMS: &[&str] = &[
  64. "hello",
  65. "world",
  66. "hello world",
  67. "hello dioxus",
  68. "hello dioxus-router",
  69. ];
  70. // Find all results that contain the query and the right number of words
  71. // This memo will automatically rerun when the query or word count changes because we read the signals inside the closure
  72. let results = use_memo(move || {
  73. ITEMS
  74. .iter()
  75. .filter(|item| {
  76. item.contains(&*query.read()) && item.split_whitespace().count() >= word_count()
  77. })
  78. .collect::<Vec<_>>()
  79. });
  80. rsx! {
  81. h1 { "Search for {query}" }
  82. input {
  83. oninput: move |e| {
  84. // Every time the query changes, we change the current route to the new query
  85. navigator().replace(Route::Search {
  86. query: e.value(),
  87. word_count: word_count(),
  88. });
  89. },
  90. value: "{query}",
  91. }
  92. input {
  93. r#type: "number",
  94. oninput: move |e| {
  95. // Every time the word count changes, we change the current route to the new query
  96. if let Ok(word_count) = e.value().parse() {
  97. navigator().replace(Route::Search {
  98. query: query(),
  99. word_count,
  100. });
  101. }
  102. },
  103. value: "{word_count}",
  104. }
  105. for result in results.read().iter() {
  106. div { "{result}" }
  107. }
  108. }
  109. }