I’m working on a project using Dioxus with routing. My problem occurs when trying to navigate to a different route in my component (src/pages/home.rs). I’m getting the following router-related
use crate::api::alpha_vantage::{AlphaVantageClient, StockData};
use dioxus::prelude::*;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
struct SearchResult {
#[serde(rename = "1. symbol")]
symbol: String,
#[serde(rename = "2. name")]
name: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
struct SearchResponse {
#[serde(rename = "bestMatches")]
best_matches: Vec<SearchResult>,
}
#[component]
pub fn HomePage() -> Element {
rsx! {
SearchComponent {}
}
}
#[component]
fn SearchComponent() -> Element {
let mut search_query = use_signal(|| String::new());
let mut search_results = use_signal(|| Vec::<SearchResult>::new());
let navigator = use_navigator();
// TODO: add debouncer
let _ = use_resource(move || async move {
let query = search_query();
if !query.is_empty() {
match search_stocks(query.clone()).await {
Ok(results) => search_results.set(results),
Err(_) => search_results.set(Vec::new()),
}
}
});
let on_select_symbol = |symbol: &str| {
// Navigate to ticker page with the selected symbol
navigator.push(Route::TickerPage {
symbol: symbol.to_string(),
});
};
rsx! {
div { class: "min-h-screen flex items-center justify-center bg-gray-100",
div { class: "bg-white shadow-lg rounded-lg p-8 max-w-lg w-full",
h1 { class: "text-4xl font-bold text-center text-gray-800", "Welcome to Stock Sage" }
p { class: "text-lg text-gray-600 text-center mt-4", "Search for a stock symbol to get started" }
div { class: "mt-6",
input {
class: "w-full p-3 border rounded-lg text-gray-700 focus:outline-none focus:ring-2 focus:ring-indigo-500",
placeholder: "Search for a stock symbol",
oninput: move |evt| search_query.set(evt.value()),
value: "{search_query}"
}
}
if !search_results().is_empty() {
div {
class: "mt-4 bg-white rounded-lg shadow-md overflow-hidden",
for result in search_results().iter() {
div {
class: "p-3 border-b hover:bg-gray-100 cursor-pointer",
onclick: move |_| on_select_symbol(&result.symbol),
h2 { class: "font-bold", "{result.symbol}" }
p { class: "text-gray-600", "{result.name}" }
}
}
}
}
}
}
}
}
async fn search_stocks(query: String) -> Result<Vec<SearchResult>, reqwest::Error> {
let client = AlphaVantageClient::new();
let url = format!(
"{}?function=SYMBOL_SEARCH&keywords={}&apikey={}",
crate::api::alpha_vantage::BASE_URL,
query,
client.api_key
);
let response: SearchResponse = client.client.get(&url).send().await?.json().await?;
Ok(response.best_matches)
}
my main.rs looks like this
#![allow(non_snake_case)]
use dioxus::prelude::*;
use dioxus_logger::tracing::{info, Level};
use stock_sage::pages::{home::HomePage, ticker::TickerPage};
#[derive(Routable, Clone, Debug, PartialEq)]
#[rustfmt::skip]
pub enum Route {
#[layout(NavBar)]
#[route("/")]
HomePage {},
#[route("/ticker/:symbol")]
TickerPage { symbol: String },
#[end_layout]
#[route("/:..route")]
PageNotFound {
route: Vec<String>,
},
}
fn main() {
dotenv::dotenv().ok();
// Init logger
dioxus_logger::init(Level::INFO).expect("failed to init logger");
info!("starting app");
let cfg = dioxus::desktop::Config::new()
.with_custom_head(r#"<link rel="stylesheet" href="tailwind.css">"#.to_string());
LaunchBuilder::desktop().with_cfg(cfg).launch(App);
}
#[component]
fn App() -> Element {
rsx! {
Router::<Route> {}
}
}
#[component]
fn NavBar() -> Element {
rsx! {
nav {
class: "bg-blue-500 p-4",
ul {
li {
Link { to: Route::HomePage {}, class: "text-white mr-4", "Home" }
Link { to: Route::TickerPage { symbol: "AAPL".to_string() }, "Apple Stock" }
}
}
}
Outlet::<Route> {}
}
}
#[component]
fn PageNotFound(route: Vec<String>) -> Element {
rsx! {
h1 { "Page not found" }
p { "We are terribly sorry, but the page you requested doesn't exist." }
pre { color: "red", "log:nattempted to navigate to: {route:?}" }
}
}
#![allow(non_snake_case)]
use dioxus::prelude::*;
use dioxus_logger::tracing::{info, Level};
use stock_sage::pages::{home::HomePage, ticker::TickerPage};
#[derive(Routable, Clone, Debug, PartialEq)]
#[rustfmt::skip]
pub enum Route {
#[layout(NavBar)]
#[route("/")]
HomePage {},
#[route("/ticker/:symbol")]
TickerPage { symbol: String },
#[end_layout]
#[route("/:..route")]
PageNotFound {
route: Vec<String>,
},
}
fn main() {
dotenv::dotenv().ok();
// Init logger
dioxus_logger::init(Level::INFO).expect("failed to init logger");
info!("starting app");
let cfg = dioxus::desktop::Config::new()
.with_custom_head(r#"<link rel="stylesheet" href="tailwind.css">"#.to_string());
LaunchBuilder::desktop().with_cfg(cfg).launch(App);
}
#[component]
fn App() -> Element {
rsx! {
Router::<Route> {}
}
}
#[component]
fn NavBar() -> Element {
rsx! {
nav {
class: "bg-blue-500 p-4",
ul {
li {
Link { to: Route::HomePage {}, class: "text-white mr-4", "Home" }
Link { to: Route::TickerPage { symbol: "AAPL".to_string() }, "Apple Stock" }
}
}
}
Outlet::<Route> {}
}
}
#[component]
fn PageNotFound(route: Vec<String>) -> Element {
rsx! {
h1 { "Page not found" }
p { "We are terribly sorry, but the page you requested doesn't exist." }
pre { color: "red", "log:nattempted to navigate to: {route:?}" }
}
}
cargo.toml
dioxus = { version = "0.5", features = ["desktop", "router"] }
# Debug
dioxus-logger = "0.5.1"
Code works fine but problems is mainly with the router i have no idea why it is not working should i export router enum or what ?
Info from cargo check:
failed to resolve: use of undeclared type `Route`
--> src/pages/home.rs:45:24
|
45 | navigator.push(Route::TickerPage {
| ^^^^^ use of undeclared type `Route`
|
help: there is an enum variant `crate::pages::home::IntoRoutable::Route` and 1 other; try using the variant's enum
|
45 | navigator.push(crate::pages::home::IntoRoutable {
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
45 | navigator.push(dioxus::prelude::IntoRoutable {
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
For more information about this error, try `rustc --explain E0433`.
warning: `stock-sage` (lib) generated 4 warnings
2