You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
let username_2 = username.clone();// This is necessary until Sycamore's new reactive primitives are released
20
+
let frozen_app = Signal::new(String::new());// This is not part of our data model, so it's not part of the state properties (everything else should be though)
// When the user visits this and then comes back, they'll still be able to see their username (the previous state will be retrieved from the global state automatically)
let global_state = ::perseus::get_render_ctx!().global_state;
190
191
let global_state = global_state.borrow();
191
192
// We can guarantee that it will downcast correctly now, because we'll only invoke the component from this function, which sets up the global state correctly
192
-
let global_state_ref = (&global_state).downcast_ref::<#global_state_rx>().unwrap();
193
+
let global_state_ref = global_state.as_any().downcast_ref::<#global_state_rx>().unwrap();
Copy file name to clipboardExpand all lines: packages/perseus/src/page_state_store.rs
+28-40
Original file line number
Diff line number
Diff line change
@@ -1,14 +1,8 @@
1
-
use std::any::{Any,TypeId};
2
1
use std::cell::RefCell;
3
2
use std::collections::HashMap;
4
3
use std::rc::Rc;
5
4
6
-
/// A key type for the `PageStateStore` that denotes both a page's state type and its URL.
7
-
#[derive(Hash,PartialEq,Eq)]
8
-
pubstructPageStateKey{
9
-
state_type:TypeId,
10
-
url:String,
11
-
}
5
+
usecrate::{rx_state::Freeze, state::AnyFreeze};
12
6
13
7
/// A container for page state in Perseus. This is designed as a context store, in which one of each type can be stored. Therefore, it acts very similarly to Sycamore's context system,
14
8
/// though it's specifically designed for each page to store one reactive properties object. In theory, you could interact with this entirely independently of Perseus' state interface,
@@ -19,47 +13,41 @@ pub struct PageStateKey {
19
13
// TODO Make this work with multiple pages for a single template
20
14
#[derive(Default,Clone)]
21
15
pubstructPageStateStore{
22
-
/// A map of type IDs to anything, allowing one storage of each type (each type is intended to a properties `struct` for a template). Entries must be `Clone`able becasue we assume them
16
+
/// A map of type IDs to anything, allowing one storage of each type (each type is intended to a properties `struct` for a template). Entries must be `Clone`able because we assume them
23
17
/// to be `Signal`s or `struct`s composed of `Signal`s.
24
18
// Technically, this should be `Any + Clone`, but that's not possible without something like `dyn_clone`, and we don't need it because we can restrict on the methods instead!
/// Gets an element out of the state by its type and URL. If the element stored for the given URL doesn't match the provided type, `None` will be returned.
/// Adds a new element to the state by its type and URL. Any existing element with the same type and URL will be silently overriden (use `.contains()` to check first if needed).
46
-
pubfnadd<T:Any + Clone>(&mutself,url:&str,val:T){
47
-
let type_id = TypeId::of::<T>();
48
-
let key = PageStateKey{
49
-
state_type: type_id,
50
-
url: url.to_string(),
51
-
};
29
+
/// Adds a new element to the state by its URL. Any existing element with the same URL will be silently overriden (use `.contains()` to check first if needed).
Copy file name to clipboardExpand all lines: packages/perseus/src/router.rs
+13-3
Original file line number
Diff line number
Diff line change
@@ -321,10 +321,20 @@ impl RouterState {
321
321
/// The current load state of the router. You can use this to be warned of when a new page is about to be loaded (and display a loading bar or the like, perhaps).
322
322
#[derive(Clone)]
323
323
pubenumRouterLoadState{
324
-
/// The page has been loaded. The name of the template is attached.
325
-
Loaded(String),
324
+
/// The page has been loaded.
325
+
Loaded{
326
+
/// The name of the template being loaded (mostly for convenience).
327
+
template_name:String,
328
+
/// The full path to the new page being loaded (including the locale, if we're using i18n).
329
+
path:String,
330
+
},
326
331
/// A new page is being loaded, and will soon replace whatever is currently loaded. The name of the new template is attached.
327
-
Loading(String),
332
+
Loading{
333
+
/// The name of the template being loaded (mostly for convenience).
334
+
template_name:String,
335
+
/// The full path to the new page being loaded (including the locale, if we're using i18n).
336
+
path:String,
337
+
},
328
338
/// We're on the server, and there is no router. Whatever you render based on this state will appear when the user first loads the page, before it's made interactive.
Copy file name to clipboardExpand all lines: packages/perseus/src/rx_state.rs
+28
Original file line number
Diff line number
Diff line change
@@ -1,3 +1,5 @@
1
+
use std::any::Any;
2
+
1
3
/// A trait for `struct`s that can be made reactive. Typically, this will be derived with the `#[make_rx]` macro, though it can be implemented manually if you have more niche requirements.
2
4
pubtraitMakeRx{
3
5
/// The type of the reactive version that we'll convert to. By having this as an associated type, we can associate the reactive type with the unreactive, meaning greater inference
@@ -16,3 +18,29 @@ pub trait MakeUnrx {
16
18
/// and fewer arguments that the user needs to provide to macros.
17
19
fnmake_unrx(self) -> Self::Unrx;
18
20
}
21
+
22
+
/// A trait for reactive `struct`s that can be made unreactive and serialized to a `String`. `struct`s that implement this should implement `MakeUnrx` for simplicity, but they technically don't have
23
+
/// to (they always do in Perseus macro-generated code).
24
+
pubtraitFreeze{
25
+
/// 'Freezes' the reactive `struct` by making it unreactive and converting it to a `String`.
26
+
fnfreeze(&self) -> String;
27
+
}
28
+
29
+
// Perseus initializes the global state as an `Option::<()>::None`, so it has to implement `Freeze`. It may seem silly, because we wouldn't want to freeze the global state if it hadn't been
30
+
// initialized, but that means it's unmodified from the server, so there would be no point in freezing it (just as there'd be no point in freezing the router state).
// Get the global state if possible (we'll want this in all cases except errors)
287
289
// If this is a subsequent load, the template macro will have already set up the global state, and it will ignore whatever we naively give it (so we'll give it `None`)
288
290
let global_state = get_global_state();
@@ -345,7 +347,7 @@ pub async fn app_shell(
345
347
let router_state_2 = router_state.clone();
346
348
// BUG (Sycamore): this will double-render if the component is just text (no nodes)
0 commit comments