Merge branch 'DioxusLabs:master' into master

This commit is contained in:
YuKun Liu authored and GitHub committed 2022-01-29 15:34:34 +08:00
commit fac58c9230
6 files changed
+93 -22

No files matched your search

+1 -13
View File
@@ -19,13 +19,7 @@ jobs:
max-parallel: 2 max-parallel: 2
fail-fast: false fail-fast: false
matrix: matrix:
target: target: [x86_64-pc-windows-gnu, x86_64-pc-windows-msvc]
[
i686-pc-windows-gnu,
i686-pc-windows-msvc,
x86_64-pc-windows-gnu,
x86_64-pc-windows-msvc,
]
cfg_release_channel: [stable] cfg_release_channel: [stable]
steps: steps:
@@ -47,12 +41,6 @@ jobs:
rustup target add ${{ matrix.target }} rustup target add ${{ matrix.target }}
shell: powershell shell: powershell
- name: Add mingw32 to path for i686-gnu
run: |
echo "C:\msys64\mingw32\bin" >> $GITHUB_PATH
if: matrix.target == 'i686-pc-windows-gnu' && matrix.channel == 'nightly'
shell: bash
- name: Add mingw64 to path for x86_64-gnu - name: Add mingw64 to path for x86_64-gnu
run: echo "C:\msys64\mingw64\bin" >> $GITHUB_PATH run: echo "C:\msys64\mingw64\bin" >> $GITHUB_PATH
if: matrix.target == 'x86_64-pc-windows-gnu' && matrix.channel == 'nightly' if: matrix.target == 'x86_64-pc-windows-gnu' && matrix.channel == 'nightly'
+39
View File
@@ -313,3 +313,42 @@ fn leak_thru_children() {
dom.handle_message(SchedulerMsg::Immediate(ScopeId(0))); dom.handle_message(SchedulerMsg::Immediate(ScopeId(0)));
dom.work_with_deadline(|| false); dom.work_with_deadline(|| false);
} }
#[test]
fn test_pass_thru() {
#[inline_props]
fn Router<'a>(cx: Scope, children: Element<'a>) -> Element {
cx.render(rsx! {
&cx.props.children
})
}
fn MemoizedThing(cx: Scope) -> Element {
rsx!(cx, div { "memoized" })
}
fn app(cx: Scope) -> Element {
let thing = cx.use_hook(|_| "asd");
rsx!(cx,
Router {
MemoizedThing {
}
}
)
}
let mut dom = new_dom(app, ());
let _ = dom.rebuild();
dom.handle_message(SchedulerMsg::Immediate(ScopeId(0)));
dom.work_with_deadline(|| false);
dom.handle_message(SchedulerMsg::Immediate(ScopeId(0)));
dom.work_with_deadline(|| false);
dom.handle_message(SchedulerMsg::Immediate(ScopeId(0)));
dom.work_with_deadline(|| false);
dom.handle_message(SchedulerMsg::Immediate(ScopeId(0)));
dom.work_with_deadline(|| false);
}
+2
View File
@@ -61,6 +61,8 @@ pub fn use_state<'a, T: 'static>(
} }
}); });
hook.current_val = hook.slot.borrow().clone();
(hook.current_val.as_ref(), hook) (hook.current_val.as_ref(), hook)
} }
+1 -1
View File
@@ -41,7 +41,7 @@ pub struct LinkProps<'a> {
} }
pub fn Link<'a>(cx: Scope<'a, LinkProps<'a>>) -> Element { pub fn Link<'a>(cx: Scope<'a, LinkProps<'a>>) -> Element {
log::debug!("render Link to {}", cx.props.to); log::trace!("render Link to {}", cx.props.to);
if let Some(service) = cx.consume_context::<RouterService>() { if let Some(service) = cx.consume_context::<RouterService>() {
return cx.render(rsx! { return cx.render(rsx! {
a { a {
+30 -7
View File
@@ -1,4 +1,4 @@
use dioxus_core::ScopeState; use dioxus_core::{ScopeId, ScopeState};
use gloo::history::{HistoryResult, Location}; use gloo::history::{HistoryResult, Location};
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
use std::{rc::Rc, str::FromStr}; use std::{rc::Rc, str::FromStr};
@@ -8,6 +8,7 @@ use crate::RouterService;
/// This struct provides is a wrapper around the internal router /// This struct provides is a wrapper around the internal router
/// implementation, with methods for getting information about the current /// implementation, with methods for getting information about the current
/// route. /// route.
#[derive(Clone)]
pub struct UseRoute { pub struct UseRoute {
router: Rc<RouterService>, router: Rc<RouterService>,
} }
@@ -74,10 +75,32 @@ impl UseRoute {
/// This hook provides access to information about the current location in the /// This hook provides access to information about the current location in the
/// context of a [`Router`]. If this function is called outside of a `Router` /// context of a [`Router`]. If this function is called outside of a `Router`
/// component it will panic. /// component it will panic.
pub fn use_route(cx: &ScopeState) -> UseRoute { pub fn use_route(cx: &ScopeState) -> &UseRoute {
let router = cx &cx.use_hook(|_| {
.consume_context::<RouterService>() let router = cx
.expect("Cannot call use_route outside the scope of a Router component") .consume_context::<RouterService>()
.clone(); .expect("Cannot call use_route outside the scope of a Router component");
UseRoute { router }
router.subscribe_onchange(cx.scope_id());
UseRouteListener {
router: UseRoute { router },
scope: cx.scope_id(),
}
})
.router
}
// The entire purpose of this struct is to unubscribe this component when it is unmounted.
// The UseRoute can be cloned into async contexts, so we can't rely on its drop to unubscribe.
// Instead, we hide the drop implementation on this private type exclusive to the hook,
// and reveal our cached version of UseRoute to the component.
struct UseRouteListener {
router: UseRoute,
scope: ScopeId,
}
impl Drop for UseRouteListener {
fn drop(&mut self) {
self.router.router.unsubscribe_onchange(self.scope)
}
} }
+20 -1
View File
@@ -1,7 +1,7 @@
use gloo::history::{BrowserHistory, History, HistoryListener, Location}; use gloo::history::{BrowserHistory, History, HistoryListener, Location};
use std::{ use std::{
cell::{Cell, Ref, RefCell}, cell::{Cell, Ref, RefCell},
collections::HashMap, collections::{HashMap, HashSet},
rc::Rc, rc::Rc,
}; };
@@ -12,6 +12,7 @@ pub struct RouterService {
pub(crate) pending_events: Rc<RefCell<Vec<RouteEvent>>>, pub(crate) pending_events: Rc<RefCell<Vec<RouteEvent>>>,
history: Rc<RefCell<BrowserHistory>>, history: Rc<RefCell<BrowserHistory>>,
slots: Rc<RefCell<Vec<(ScopeId, String)>>>, slots: Rc<RefCell<Vec<(ScopeId, String)>>>,
onchange_listeners: Rc<RefCell<HashSet<ScopeId>>>,
root_found: Rc<Cell<Option<ScopeId>>>, root_found: Rc<Cell<Option<ScopeId>>>,
cur_path_params: Rc<RefCell<HashMap<String, String>>>, cur_path_params: Rc<RefCell<HashMap<String, String>>>,
listener: HistoryListener, listener: HistoryListener,
@@ -42,6 +43,7 @@ impl RouterService {
let location = history.location(); let location = history.location();
let path = location.path(); let path = location.path();
let onchange_listeners = Rc::new(RefCell::new(HashSet::new()));
let slots: Rc<RefCell<Vec<(ScopeId, String)>>> = Default::default(); let slots: Rc<RefCell<Vec<(ScopeId, String)>>> = Default::default();
let pending_events: Rc<RefCell<Vec<RouteEvent>>> = Default::default(); let pending_events: Rc<RefCell<Vec<RouteEvent>>> = Default::default();
let root_found = Rc::new(Cell::new(None)); let root_found = Rc::new(Cell::new(None));
@@ -51,6 +53,7 @@ impl RouterService {
let regen_route = regen_route.clone(); let regen_route = regen_route.clone();
let root_found = root_found.clone(); let root_found = root_found.clone();
let slots = slots.clone(); let slots = slots.clone();
let onchange_listeners = onchange_listeners.clone();
move || { move || {
root_found.set(None); root_found.set(None);
// checking if the route is valid is cheap, so we do it // checking if the route is valid is cheap, so we do it
@@ -59,6 +62,11 @@ impl RouterService {
regen_route(*slot); regen_route(*slot);
} }
for listener in onchange_listeners.borrow_mut().iter() {
log::trace!("regenerating listener {:?}", listener);
regen_route(*listener);
}
// also regenerate the root // also regenerate the root
regen_route(root_scope); regen_route(root_scope);
@@ -73,6 +81,7 @@ impl RouterService {
regen_route, regen_route,
slots, slots,
pending_events, pending_events,
onchange_listeners,
cur_path_params: Rc::new(RefCell::new(HashMap::new())), cur_path_params: Rc::new(RefCell::new(HashMap::new())),
} }
} }
@@ -143,6 +152,16 @@ impl RouterService {
pub fn current_path_params(&self) -> Ref<HashMap<String, String>> { pub fn current_path_params(&self) -> Ref<HashMap<String, String>> {
self.cur_path_params.borrow() self.cur_path_params.borrow()
} }
pub fn subscribe_onchange(&self, id: ScopeId) {
log::trace!("Subscribing onchange for scope id {:?}", id);
self.onchange_listeners.borrow_mut().insert(id);
}
pub fn unsubscribe_onchange(&self, id: ScopeId) {
log::trace!("Subscribing onchange for scope id {:?}", id);
self.onchange_listeners.borrow_mut().remove(&id);
}
} }
fn clean_route(route: String) -> String { fn clean_route(route: String) -> String {