wip: docs and router

This commit is contained in:
Jonathan Kelley committed 2021-11-19 00:49:04 -05:00
1 parent 8bf57dc21d
commit a5f05d73ac
50 files changed
+1263 -234

No files matched your search

+6
View File
@@ -37,3 +37,9 @@ default = ["web"]
web = ["web-sys"]
desktop = []
mobile = []
[dev-dependencies]
console_error_panic_hook = "0.1.7"
dioxus-web = { path = "../web" }
log = "0.4.14"
wasm-logger = "0.2.0"
+40
View File
@@ -0,0 +1,40 @@
# Router hook for Dioxus apps
Dioxus-router provides a use_router hook that returns a different value depending on the route.
The router is generic over any value, however it makes sense to return a different set of VNodes
and feed them into the App's return VNodes.
Using the router should feel similar to tide's routing framework where an "address" book is assembled at the head of the app.
Here's an example of how to use the router hook:
```rust
#[derive(Clone, Routable)]
enum AppRoute {
Home,
Posts,
NotFound
}
static App: FC<()> = |cx, props| {
let route = use_router(cx, AppRoute::parse);
match route {
AppRoute::Home => rsx!(cx, Home {})
AppRoute::Posts => rsx!(cx, Posts {})
AppRoute::Notfound => rsx!(cx, Notfound {})
}
};
```
Adding links into your app:
```rust
static Leaf: FC<()> = |cx, props| {
rsx!(cx, div {
Link { to: AppRoute::Home }
})
}
```
Currently, the router is only supported in a web environment, but we plan to add 1st-party support via the context API when new renderers are available.
+45
View File
@@ -0,0 +1,45 @@
use dioxus_core::prelude::*;
use dioxus_core_macro::*;
use dioxus_html as dioxus_elements;
use dioxus_router::*;
fn main() {
console_error_panic_hook::set_once();
dioxus_web::launch(App, |c| c);
}
#[derive(Clone, Debug, PartialEq)]
enum Route {
Home,
About,
NotFound,
}
static App: FC<()> = |cx, props| {
let route = use_router(cx, Route::parse);
match route {
Route::Home => rsx!(cx, div { "Home" }),
Route::About => rsx!(cx, div { "About" }),
Route::NotFound => rsx!(cx, div { "NotFound" }),
}
};
impl ToString for Route {
fn to_string(&self) -> String {
match self {
Route::Home => "/".to_string(),
Route::About => "/about".to_string(),
Route::NotFound => "/404".to_string(),
}
}
}
impl Route {
fn parse(s: &str) -> Self {
match s {
"/" => Route::Home,
"/about" => Route::About,
_ => Route::NotFound,
}
}
}
+13 -23
View File
@@ -11,14 +11,18 @@ use web_sys::Event;
use crate::utils::fetch_base_url;
pub trait Routable: 'static + Send + Clone + ToString + PartialEq {}
impl<T> Routable for T where T: 'static + Send + Clone + ToString + PartialEq {}
pub struct RouterService<R: Routable> {
history: RefCell<Vec<R>>,
historic_routes: RefCell<Vec<R>>,
history_service: web_sys::History,
base_ur: RefCell<Option<String>>,
}
impl<R: Routable> RouterService<R> {
fn push_route(&self, r: R) {
self.history.borrow_mut().push(r);
self.historic_routes.borrow_mut().push(r);
}
fn get_current_route(&self) -> &str {
@@ -61,7 +65,7 @@ impl<R: Routable> RouterService<R> {
/// This hould only be used once per app
///
/// You can manually parse the route if you want, but the derived `parse` method on `Routable` will also work just fine
pub fn use_router<R: Routable>(cx: Context, cfg: impl FnOnce(&str) -> R) -> Option<&R> {
pub fn use_router<R: Routable>(cx: Context, parse: impl FnMut(&str) -> R) -> &R {
// for the web, attach to the history api
cx.use_hook(
|f| {
@@ -71,10 +75,13 @@ pub fn use_router<R: Routable>(cx: Context, cfg: impl FnOnce(&str) -> R) -> Opti
let base_url = fetch_base_url();
let service: RouterService<R> = RouterService {
history: RefCell::new(vec![]),
historic_routes: RefCell::new(vec![]),
history_service: web_sys::window().unwrap().history().expect("no history"),
base_ur: RefCell::new(base_url),
};
// service.history_service.push_state(data, title);
cx.provide_state(service);
let regenerate = cx.schedule_update();
@@ -105,30 +112,13 @@ pub struct LinkProps<R: Routable> {
children: Element,
}
pub fn Link<'a, R: Routable>(cx: Context, props: &LinkProps<R>) -> Element {
pub fn Link<R: Routable>(cx: Context, props: &LinkProps<R>) -> Element {
let service = use_router_service::<R>(cx)?;
cx.render(rsx! {
a {
href: format_args!("{}", props.to.to_path()),
href: format_args!("{}", props.to.to_string()),
onclick: move |_| service.push_route(props.to.clone()),
{&props.children},
}
})
}
pub trait Routable: Sized + Clone + 'static {
/// Converts path to an instance of the routes enum.
fn from_path(path: &str, params: &HashMap<&str, &str>) -> Option<Self>;
/// Converts the route to a string that can passed to the history API.
fn to_path(&self) -> String;
/// Lists all the available routes
fn routes() -> Vec<&'static str>;
/// The route to redirect to on 404
fn not_found_route() -> Option<Self>;
/// Match a route based on the path
fn recognize(pathname: &str) -> Option<Self>;
}