mirror of
https://github.com/leptos-rs/leptos
synced 2024-11-10 06:44:17 +00:00
Router example
This commit is contained in:
parent
d6c007dcc4
commit
89d30d017c
3 changed files with 140 additions and 50 deletions
|
@ -2,6 +2,17 @@
|
|||
<html>
|
||||
<head>
|
||||
<link data-trunk rel="rust" data-wasm-opt="z"/>
|
||||
<style>
|
||||
a.active {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.contact, .contact-list {
|
||||
border: 1px solid #c0c0c0;
|
||||
border-radius: 3px;
|
||||
padding: 1rem;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body></body>
|
||||
</html>
|
|
@ -29,17 +29,29 @@ pub struct Contact {
|
|||
|
||||
pub async fn get_contacts(search: String) -> Vec<ContactSummary> {
|
||||
// fake an API call with an artificial delay
|
||||
delay(Duration::from_millis(100)).await;
|
||||
vec![ContactSummary {
|
||||
delay(Duration::from_millis(300)).await;
|
||||
vec![
|
||||
ContactSummary {
|
||||
id: 0,
|
||||
first_name: "Bill".into(),
|
||||
last_name: "Smith".into(),
|
||||
}]
|
||||
},
|
||||
ContactSummary {
|
||||
id: 1,
|
||||
first_name: "Tim".into(),
|
||||
last_name: "Jones".into(),
|
||||
},
|
||||
ContactSummary {
|
||||
id: 2,
|
||||
first_name: "Sally".into(),
|
||||
last_name: "Stevens".into(),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
pub async fn get_contact(id: Option<usize>) -> Option<Contact> {
|
||||
// fake an API call with an artificial delay
|
||||
delay(Duration::from_millis(350)).await;
|
||||
delay(Duration::from_millis(500)).await;
|
||||
match id {
|
||||
Some(0) => Some(Contact {
|
||||
id: 0,
|
||||
|
@ -53,6 +65,30 @@ pub async fn get_contact(id: Option<usize>) -> Option<Contact> {
|
|||
email: "bill@smith.com".into(),
|
||||
phone: "617-121-1221".into(),
|
||||
}),
|
||||
Some(1) => Some(Contact {
|
||||
id: 1,
|
||||
first_name: "Tim".into(),
|
||||
last_name: "Jones".into(),
|
||||
address_1: "56 Main Street".into(),
|
||||
address_2: "".into(),
|
||||
city: "Chattanooga".into(),
|
||||
state: "TN".into(),
|
||||
zip: "13371".into(),
|
||||
email: "timjones@lmail.com".into(),
|
||||
phone: "232-123-1337".into(),
|
||||
}),
|
||||
Some(2) => Some(Contact {
|
||||
id: 2,
|
||||
first_name: "Sally".into(),
|
||||
last_name: "Stevens".into(),
|
||||
address_1: "404 E 123rd St".into(),
|
||||
address_2: "Apt 7E".into(),
|
||||
city: "New York".into(),
|
||||
state: "NY".into(),
|
||||
zip: "10082".into(),
|
||||
email: "sally.stevens@wahoo.net".into(),
|
||||
phone: "242-121-3789".into(),
|
||||
}),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,105 +13,148 @@ use crate::api::{get_contact, get_contacts};
|
|||
|
||||
fn contact_list(
|
||||
cx: Scope,
|
||||
params: ParamsMap,
|
||||
params: Memo<ParamsMap>,
|
||||
location: Location,
|
||||
) -> Resource<String, Vec<ContactSummary>> {
|
||||
log::debug!("(contact_list) reloading contact list");
|
||||
create_resource(cx, location.search, move |s| get_contacts(s.to_string()))
|
||||
create_resource(cx, location.search, get_contacts)
|
||||
}
|
||||
|
||||
fn contact(
|
||||
cx: Scope,
|
||||
params: ParamsMap,
|
||||
params: Memo<ParamsMap>,
|
||||
location: Location,
|
||||
) -> Resource<Option<usize>, Option<Contact>> {
|
||||
log::debug!("(contact) reloading contact");
|
||||
create_resource(
|
||||
cx,
|
||||
move || {
|
||||
params
|
||||
params()
|
||||
.get("id")
|
||||
.cloned()
|
||||
.unwrap_or_default()
|
||||
.parse::<usize>()
|
||||
.ok()
|
||||
},
|
||||
move |id| get_contact(id),
|
||||
get_contact,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn router_example(cx: Scope) -> Element {
|
||||
view! {
|
||||
<div>
|
||||
<nav>
|
||||
<a href="/">"Contacts"</a>
|
||||
<a href="/about">"About"</a>
|
||||
<a href="/settings">"Settings"</a>
|
||||
</nav>
|
||||
<main>
|
||||
<Router
|
||||
mode=BrowserIntegration {}
|
||||
base="/"
|
||||
>
|
||||
<Routes>
|
||||
<Route path=""
|
||||
element=move |cx| view! { <Index/> }
|
||||
>
|
||||
<Route
|
||||
path=""
|
||||
element=move || view! { <ContactList/> }
|
||||
path="contacts"
|
||||
element=move |cx| view! { <ContactList/> }
|
||||
loader=contact_list.into()
|
||||
>
|
||||
<Route
|
||||
path=":id"
|
||||
loader=contact.into()
|
||||
element=move || view! { <Contact/> }
|
||||
element=move |cx| view! { <Contact/> }
|
||||
/>
|
||||
<Route
|
||||
path="about"
|
||||
loader=contact.into()
|
||||
element=move |cx| view! { <p class="contact">"Here is your list of contacts"</p> }
|
||||
/>
|
||||
<Route
|
||||
path=""
|
||||
loader=contact.into()
|
||||
element=move |cx| view! { <p class="contact">"Select a contact."</p> }
|
||||
/>
|
||||
</Route>
|
||||
<Route
|
||||
path="about"
|
||||
element=move || view! { <About/> }
|
||||
element=move |cx| view! { <About/> }
|
||||
/>
|
||||
<Route
|
||||
path="settings"
|
||||
element=move || view! { <Settings/> }
|
||||
element=move |cx| view! { <Settings/> }
|
||||
/>
|
||||
</Route>
|
||||
</Routes>
|
||||
</Router>
|
||||
</main>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
#[component]
|
||||
pub fn ContactList(cx: Scope) -> Vec<Element> {
|
||||
let contacts = use_loader::<Resource<String, Vec<ContactSummary>>>(cx);
|
||||
|
||||
pub fn Index(cx: Scope) -> Vec<Element> {
|
||||
view! {
|
||||
<>
|
||||
<h1>"Contacts"</h1>
|
||||
<ul>
|
||||
<For each={move || contacts.read().unwrap_or_default()} key=|contact| contact.id>
|
||||
{|cx, contact: &ContactSummary| {
|
||||
view! {
|
||||
<li><a href=format!("/contacts/{}", contact.id)> {&contact.first_name} " " {&contact.last_name}</a></li>
|
||||
}
|
||||
}}
|
||||
</For>
|
||||
</ul>
|
||||
<div><Outlet/></div>
|
||||
<nav>
|
||||
<NavLink to="contacts".into()>"Contacts"</NavLink>
|
||||
<NavLink to="about".into()>"About"</NavLink>
|
||||
<NavLink to="settings".into()>"Settings"</NavLink>
|
||||
</nav>
|
||||
<main><Outlet/></main>
|
||||
</>
|
||||
}
|
||||
}
|
||||
|
||||
#[component]
|
||||
pub fn Contact(cx: Scope) -> Element {
|
||||
//let contact = use_loader::<Resource<Option<usize>, Option<Contact>>>(cx);
|
||||
pub fn ContactList(cx: Scope) -> Element {
|
||||
let contacts = use_loader::<Resource<String, Vec<ContactSummary>>>(cx);
|
||||
|
||||
log::debug!(
|
||||
"[ContactList] before <Suspense/>, use_route(cx).path() is {:?}",
|
||||
use_route(cx).path()
|
||||
);
|
||||
|
||||
view! {
|
||||
<pre>"Contact info here"</pre>
|
||||
<div class="contact-list">
|
||||
<h1>"Contacts"</h1>
|
||||
<Link to="about".into()>"About"</Link>
|
||||
<NavLink to={0.to_string()}>"Link to first contact"</NavLink>
|
||||
<ul>
|
||||
<Suspense fallback=move || view! { <p>"Loading contacts..."</p> }>{
|
||||
move || {
|
||||
log::debug!("[ContactList] inside <Suspense/>, use_route(cx) is now {:?}", use_route(cx).path());
|
||||
view! {
|
||||
<For each={move || contacts.read().unwrap_or_default()} key=|contact| contact.id>
|
||||
{move |cx, contact: &ContactSummary| {
|
||||
view! {
|
||||
<li><NavLink to={contact.id.to_string()}><span>{&contact.first_name} " " {&contact.last_name}</span></NavLink></li>
|
||||
}
|
||||
}}
|
||||
</For>
|
||||
}
|
||||
}
|
||||
}</Suspense>
|
||||
</ul>
|
||||
<Outlet/>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
#[component]
|
||||
pub fn About(cx: Scope) -> Vec<Element> {
|
||||
pub fn Contact(cx: Scope) -> Element {
|
||||
let contact = use_loader::<Resource<Option<usize>, Option<Contact>>>(cx);
|
||||
|
||||
view! {
|
||||
<div class="contact">
|
||||
<Suspense fallback=move || view! { <p>"Loading..."</p> }>{
|
||||
move || contact.read().flatten().map(|contact| view! {
|
||||
<section class="card">
|
||||
<h1>{contact.first_name} " " {contact.last_name}</h1>
|
||||
<p>{contact.address_1}<br/>{contact.address_2}</p>
|
||||
</section>
|
||||
})
|
||||
}</Suspense>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
#[component]
|
||||
pub fn About(_cx: Scope) -> Vec<Element> {
|
||||
view! {
|
||||
<>
|
||||
<h1>"About"</h1>
|
||||
|
@ -121,7 +164,7 @@ pub fn About(cx: Scope) -> Vec<Element> {
|
|||
}
|
||||
|
||||
#[component]
|
||||
pub fn Settings(cx: Scope) -> Vec<Element> {
|
||||
pub fn Settings(_cx: Scope) -> Vec<Element> {
|
||||
view! {
|
||||
<>
|
||||
<h1>"Settings"</h1>
|
||||
|
|
Loading…
Reference in a new issue