-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
WIP for a Kobold router #95
Conversation
crates/kobold_router/src/lib.rs
Outdated
#[component(class?: "".to_string())] | ||
pub fn router_link(route: VString, text: VString, class: String) -> impl View + 'static { | ||
// A router link component for using kobold_router | ||
stateful( | ||
|| RouteLink::new(route, text, class.into()), | ||
|route_link: &Hook<RouteLink>| { | ||
let onclick = move |event: MouseEvent<HtmlLinkElement>| { | ||
navigate(route_link.route.as_str()); | ||
event.prevent_default(); | ||
}; | ||
|
||
view! { | ||
|
||
<a class={route_link.class_names.clone()} href={route_link.route.clone()} style="text-decoration: underline;" onclick={onclick}> {&route_link.text}</a> | ||
} | ||
}, | ||
) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Gonna start here :D
Something simple like this would work:
#[component(class?: "")]
// It's fine to call this just `link` given it's likely to be used a lot I think
pub fn link<'a>(route: &'a str, class: &'a str, children: impl View + 'a) -> impl View + 'a {
// Only need to turn the string into an owned string here...
let route = String::from(route);
// ...so we can move it inside the closure giving `onclick`
// a `'static` lifetime
let onclick = move |event: MouseEvent<_>| {
// If you have a function that takes `&str` and you have a `String`
// or something similar, the idiomatic thing to do is to just pass
// a simple `&String` reference, and let the compiler deref it.
navigate(&route);
event.prevent_default();
};
view! {
<a {class} {onclick}>{children}</a>
}
}
Not documented yet but since 0.10 you don't have to decorate a component with #[component(children)]
to accept children, so both of these will work:
view! {
<!link route={"/foo"}><strong>"This is a bold link to /foo"</strong></!link>
<!link route={"/bar"} children={"This is a text link to /bar"}>
}
Ideally we should avoid doing allocations inside components (the String::from
, .into()
when the type is known, etc.) since those are called on every render. I have a fence
for this, but it currently only works for View
s, not event listeners, though that should be an easy enough addition I can help you with ("just" need to implement IntoListener<E>
for Fence
but there is a lot of generic types at play there). Then this function could look like this:
#[component(class?: "")]
pub fn link<'a>(route: &'a str, class: &'a str, children: impl View + 'a) -> impl View + 'a {
let onclick = fence(route, || {
let route = String::from(route);
move |event: MouseEvent<_>| {
navigate(&route);
event.prevent_default();
}
});
view! {
<a {class} {onclick}>{children}</a>
}
}
Sidenote: yes that 'a
all over the signature is ugly as hell, but come Rust 2024 edition (should come october) we'll be able to remove it!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I appreciate all the details, and it was a big help! I could not get IntoListener<E>
for Fence
, so I took the first example you provided. However, I did add a clone to pass the route to the href attribute. I needed that attribute set for the browser's built-in styling. Was not sure if there was a better way or not.
c777c2d
to
7afc92e
Compare
I have hit all the goals I had in the original draft post 🎉. At this point I have hit everything I can see for an initial router besides what is listed at the bottom. I think this is a decent start I think that can be built on. So I am going flip the PR to publish. Please let me know of any performance changes or suggestions you may have! Implementation details and explanations
Current improvements I see and will look into in the future
|
TODOS
matchit::Router<>
, probably a fn -> JsValue that can take a paramArc<Mutex<Routes>>
toRc<RefCell<Routes>>
pushstate
for routing and create navigation methods