Yew: Get previous route (yew router)

Created on 25 Aug 2020  路  2Comments  路  Source: yewstack/yew


Question

does Yew Router provide to get the previous route like react-router-last-location?
I haven't seen anything in the documentation about it

question router

Most helpful comment

No, the router does not keep track of the history. The state and history is handled by the Javascript History API which only allows access to the current state (that's also the reason why react-router-last-location has that big disclaimer "Last location != Previous browser history state").

You can however manually keep track of the previous route. To do this you can connect to the RouteAgent which will notify you whenever the route is changed.
You can then keep track of the current route and assign it to the previous route whenever the route changes.

Here's a complete example:

use std::mem;
use wasm_bindgen::prelude::*;
use yew::{html, Component, ComponentLink, Html, ShouldRender};
use yew_router::{
    agent::RouteAgentBridge, components::RouterButton, route::Route, service::RouteService, Switch,
};

#[derive(Debug, Switch, Clone)]
pub enum AppRoute {
    #[to = "/a/{anything}"]
    A(String),
    #[to = "/b/{anything}"]
    B(String),
    #[to = "/c"]
    C,
}

type AppRouterButton = RouterButton<AppRoute>;

pub enum Msg {
    UpdateRoute(Route<()>),
}

pub struct Model {
    _route_agent: RouteAgentBridge,
    route: Route,
    previous_route: Option<Route>,
}
impl Component for Model {
    type Message = Msg;
    type Properties = ();

    fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
        let callback = link.callback(Msg::UpdateRoute);
        let route_agent = RouteAgentBridge::new(callback);

        let route = RouteService::new().get_route();

        Self {
            _route_agent: route_agent,
            route,
            previous_route: None,
        }
    }

    fn update(&mut self, msg: Self::Message) -> ShouldRender {
        match msg {
            Msg::UpdateRoute(route) => {
                let old_route = mem::replace(&mut self.route, route);
                self.previous_route = Some(old_route);
                true
            }
        }
    }

    fn change(&mut self, _: Self::Properties) -> ShouldRender {
        false
    }

    fn view(&self) -> Html {
        html! {
            <div>
                <nav class="menu">
                    <AppRouterButton route=AppRoute::A("lorem".to_string())>{ "A" }</AppRouterButton>
                    <AppRouterButton route=AppRoute::B("hello".to_string())>{ "B" }</AppRouterButton>
                    <AppRouterButton route=AppRoute::C>{ "C" }</AppRouterButton>
                </nav>
                <div>
                    { format!("current route: {:#?}", self.route) }
                    <br />
                    { format!("previous route: {:#?}", self.previous_route) }
                </div>
            </div>
        }
    }
}

#[wasm_bindgen(start)]
pub fn run_app() {
    yew::start_app::<Model>();
}

Note: This example only keeps track of the previous route, it does not store the entire history. If you need that functionality you need to store the routes in a vector.

All 2 comments

No, the router does not keep track of the history. The state and history is handled by the Javascript History API which only allows access to the current state (that's also the reason why react-router-last-location has that big disclaimer "Last location != Previous browser history state").

You can however manually keep track of the previous route. To do this you can connect to the RouteAgent which will notify you whenever the route is changed.
You can then keep track of the current route and assign it to the previous route whenever the route changes.

Here's a complete example:

use std::mem;
use wasm_bindgen::prelude::*;
use yew::{html, Component, ComponentLink, Html, ShouldRender};
use yew_router::{
    agent::RouteAgentBridge, components::RouterButton, route::Route, service::RouteService, Switch,
};

#[derive(Debug, Switch, Clone)]
pub enum AppRoute {
    #[to = "/a/{anything}"]
    A(String),
    #[to = "/b/{anything}"]
    B(String),
    #[to = "/c"]
    C,
}

type AppRouterButton = RouterButton<AppRoute>;

pub enum Msg {
    UpdateRoute(Route<()>),
}

pub struct Model {
    _route_agent: RouteAgentBridge,
    route: Route,
    previous_route: Option<Route>,
}
impl Component for Model {
    type Message = Msg;
    type Properties = ();

    fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
        let callback = link.callback(Msg::UpdateRoute);
        let route_agent = RouteAgentBridge::new(callback);

        let route = RouteService::new().get_route();

        Self {
            _route_agent: route_agent,
            route,
            previous_route: None,
        }
    }

    fn update(&mut self, msg: Self::Message) -> ShouldRender {
        match msg {
            Msg::UpdateRoute(route) => {
                let old_route = mem::replace(&mut self.route, route);
                self.previous_route = Some(old_route);
                true
            }
        }
    }

    fn change(&mut self, _: Self::Properties) -> ShouldRender {
        false
    }

    fn view(&self) -> Html {
        html! {
            <div>
                <nav class="menu">
                    <AppRouterButton route=AppRoute::A("lorem".to_string())>{ "A" }</AppRouterButton>
                    <AppRouterButton route=AppRoute::B("hello".to_string())>{ "B" }</AppRouterButton>
                    <AppRouterButton route=AppRoute::C>{ "C" }</AppRouterButton>
                </nav>
                <div>
                    { format!("current route: {:#?}", self.route) }
                    <br />
                    { format!("previous route: {:#?}", self.previous_route) }
                </div>
            </div>
        }
    }
}

#[wasm_bindgen(start)]
pub fn run_app() {
    yew::start_app::<Model>();
}

Note: This example only keeps track of the previous route, it does not store the entire history. If you need that functionality you need to store the routes in a vector.

I think that is what I need. Thanks a lot!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

IngwiePhoenix picture IngwiePhoenix  路  4Comments

zethra picture zethra  路  5Comments

kellytk picture kellytk  路  4Comments

Boscop picture Boscop  路  5Comments

FrontMage picture FrontMage  路  4Comments