Router

Percy provides a route that can be used for deciding which views to render based on, say, the route that the user has visited in their browser.

Here's an example


#![allow(unused)]
fn main() {
// Imported from crates/percy-router-macro-test/src/book_example.rs

use percy_dom::prelude::*;
use percy_router::prelude::*;
use std::str::FromStr;

mod my_routes {
    use super::*;

    #[route(path = "/users/:id/favorite-meal/:meal", on_visit = download_some_data)]
    pub(super) fn route_data_and_param(
        id: u16,
        state: Provided<SomeState>,
        meal: Meal,
    ) -> VirtualNode {
        let id = format!("{}", id);
        let meal = format!("{:#?}", meal);

        html! {
            <div> User { id } loves { meal } </div>
        }
    }
}

fn download_some_data(id: u16, state: Provided<SomeState>, meal: Meal) {
    // Check state to see if we've already downloaded data ...
    // If not - download the data that we need
}

#[test]
fn provided_data_and_param() {
    let mut router = Router::new(create_routes![my_routes::route_data_and_param]);
    router.provide(SomeState { happy: true });

    assert_eq!(
        &router
            .view("/users/10/favorite-meal/breakfast")
            .unwrap()
            .to_string(),
        // TODO: Requires proc macro APIs that are currently unstable - https://github.com/rust-lang/rust/issues/54725
        //         "<div> User 10 loves Breakfast </div>"
        "<div>User10lovesBreakfast</div>"
    );
}

struct SomeState {
    happy: bool,
}

#[derive(Debug)]
enum Meal {
    Breakfast,
    Lunch,
    Dinner,
}

impl FromStr for Meal {
    type Err = ();

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Ok(match s {
            "breakfast" => Meal::Breakfast,
            "lunch" => Meal::Lunch,
            "dinner" => Meal::Dinner,
            _ => Err(())?,
        })
    }
}
}

This section will dive into how that works.