Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 50 additions & 62 deletions packages/yew-router/src/router.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
//! Router Component.
use std::rc::Rc;

use crate::prelude::*;
use yew::prelude::*;
Expand Down Expand Up @@ -30,78 +31,65 @@ impl PartialEq for RouterState {
}
}

#[doc(hidden)]
pub enum Msg {
ReRender,
pub(crate) enum RouterStateAction {
Navigate,
ReplaceHistory(AnyHistory),
}

/// The Router component.
///
/// This provides [`History`] context to its children and switches.
///
/// You only need one `<Router />` for each application.
pub struct Router {
_listener: HistoryListener,
history: AnyHistory,
ctr: u32,
}
impl Reducible for RouterState {
type Action = RouterStateAction;

impl Component for Router {
type Message = Msg;
type Properties = RouterProps;

fn create(ctx: &Context<Self>) -> Self {
let link = ctx.link().clone();

let listener = ctx
.props()
.history
.listen(move || link.send_message(Msg::ReRender));
fn reduce(self: Rc<Self>, action: Self::Action) -> Rc<Self> {
let history = match action {
RouterStateAction::Navigate => self.history(),
RouterStateAction::ReplaceHistory(m) => m,
};

Self {
_listener: listener,
history: ctx.props().history.clone(),
ctr: 0,
history,
ctr: self.ctr + 1,
}
.into()
}
}

fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
match msg {
Msg::ReRender => {
self.ctr += 1;
true
}
}
}

fn changed(&mut self, ctx: &Context<Self>) -> bool {
let link = ctx.link().clone();

if self.history != ctx.props().history {
self._listener = ctx
.props()
.history
.listen(move || link.send_message(Msg::ReRender));

self.history = ctx.props().history.clone();

true
} else {
false
}
/// The Router component.
///
/// This provides [`History`] context to its children and switches.
///
/// You only need one `<Router />` for each application.
#[function_component(Router)]
pub fn router(props: &RouterProps) -> Html {
let RouterProps { history, children } = props.clone();

let state = use_reducer(|| RouterState {
Comment thread
futursolo marked this conversation as resolved.
history: history.clone(),
ctr: 0,
});

{
let state_dispatcher = state.dispatcher();

use_effect_with_deps(
move |history| {
state_dispatcher.dispatch(RouterStateAction::ReplaceHistory(history.clone()));

let listener =
history.listen(move || state_dispatcher.dispatch(RouterStateAction::Navigate));

// We hold the listener in the destructor.
move || {
std::mem::drop(listener);
}
},
history,
);
}

fn view(&self, ctx: &Context<Self>) -> Html {
let state = RouterState {
history: self.history.clone().into_any_history(),
ctr: self.ctr,
};

html! {
<ContextProvider<RouterState> context={state}>
{ctx.props().children.clone()}
</ContextProvider<RouterState>>
}
html! {
<ContextProvider<RouterState> context={(*state).clone()}>
{children}
</ContextProvider<RouterState>>
}
}

Expand Down