diff --git a/packages/yew-router/src/router.rs b/packages/yew-router/src/router.rs
index 785ad6d36b3..8c2e2bca7d9 100644
--- a/packages/yew-router/src/router.rs
+++ b/packages/yew-router/src/router.rs
@@ -1,4 +1,5 @@
//! Router Component.
+use std::rc::Rc;
use crate::prelude::*;
use yew::prelude::*;
@@ -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 `` 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 {
- let link = ctx.link().clone();
-
- let listener = ctx
- .props()
- .history
- .listen(move || link.send_message(Msg::ReRender));
+ fn reduce(self: Rc, action: Self::Action) -> Rc {
+ 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, msg: Self::Message) -> bool {
- match msg {
- Msg::ReRender => {
- self.ctr += 1;
- true
- }
- }
- }
-
- fn changed(&mut self, ctx: &Context) -> 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 `` for each application.
+#[function_component(Router)]
+pub fn router(props: &RouterProps) -> Html {
+ let RouterProps { history, children } = props.clone();
+
+ let state = use_reducer(|| RouterState {
+ 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) -> Html {
- let state = RouterState {
- history: self.history.clone().into_any_history(),
- ctr: self.ctr,
- };
-
- html! {
- context={state}>
- {ctx.props().children.clone()}
- >
- }
+ html! {
+ context={(*state).clone()}>
+ {children}
+ >
}
}