This is unreleased documentation for Yew Next version.
For up-to-date documentation, see the latest version on docs.rs.

yew_router/components/
link.rs

1use serde::Serialize;
2use wasm_bindgen::UnwrapThrowExt;
3use yew::prelude::*;
4use yew::virtual_dom::AttrValue;
5
6use crate::navigator::NavigatorKind;
7use crate::prelude::*;
8use crate::{utils, Routable};
9
10/// Props for [`Link`]
11#[derive(Properties, Clone, PartialEq)]
12pub struct LinkProps<R, Q = (), S = ()>
13where
14    R: Routable,
15    Q: Clone + PartialEq + Serialize,
16    S: Clone + PartialEq,
17{
18    /// CSS classes to add to the anchor element (optional).
19    #[prop_or_default]
20    pub classes: Classes,
21    /// Route that will be pushed when the anchor is clicked.
22    pub to: R,
23    /// Route query data
24    #[prop_or_default]
25    pub query: Option<Q>,
26    /// Route state data
27    #[prop_or_default]
28    pub state: Option<S>,
29    #[prop_or_default]
30    pub disabled: bool,
31    /// [`NodeRef`](yew::html::NodeRef) for the `<a>` element.
32    #[prop_or_default]
33    pub anchor_ref: NodeRef,
34    #[prop_or_default]
35    pub children: Html,
36}
37
38/// A wrapper around `<a>` tag to be used with [`Router`](crate::Router)
39#[function_component]
40pub fn Link<R, Q = (), S = ()>(props: &LinkProps<R, Q, S>) -> Html
41where
42    R: Routable + 'static,
43    Q: Clone + PartialEq + Serialize + 'static,
44    S: Clone + PartialEq + 'static,
45{
46    let LinkProps {
47        classes,
48        to,
49        query,
50        state,
51        disabled,
52        anchor_ref,
53        children,
54    } = props.clone();
55
56    let navigator = use_navigator().expect_throw("failed to get navigator");
57
58    let onclick = {
59        let navigator = navigator.clone();
60        let to = to.clone();
61        let query = query.clone();
62        let state = state.clone();
63
64        Callback::from(move |e: MouseEvent| {
65            if e.meta_key() || e.ctrl_key() || e.shift_key() || e.alt_key() {
66                return;
67            }
68            e.prevent_default();
69            match (&state, &query) {
70                (None, None) => {
71                    navigator.push(&to);
72                }
73                (Some(state), None) => {
74                    navigator.push_with_state(&to, state.clone());
75                }
76                (None, Some(query)) => {
77                    navigator
78                        .push_with_query(&to, query)
79                        .expect_throw("failed push history with query");
80                }
81                (Some(state), Some(query)) => {
82                    navigator
83                        .push_with_query_and_state(&to, query, state.clone())
84                        .expect_throw("failed push history with query and state");
85                }
86            }
87        })
88    };
89
90    let href = {
91        let route_s = to.to_path();
92        let pathname = navigator.prefix_basename(&route_s);
93        let mut path = query
94            .and_then(|query| serde_urlencoded::to_string(query).ok())
95            .and_then(|query| utils::compose_path(&pathname, &query))
96            .unwrap_or_else(|| pathname.into_owned());
97
98        if navigator.kind() == NavigatorKind::Hash {
99            path.insert(0, '#');
100        }
101
102        AttrValue::from(path)
103    };
104
105    html! {
106        <a class={classes}
107            {href}
108            {onclick}
109            {disabled}
110            ref={anchor_ref}
111        >
112            { children }
113        </a>
114    }
115}