Skip to content

Commit c0c30b6

Browse files
committed
docs: updated template macro docs for no args
We no longer need args for it since the ability to infer component names was added.
1 parent 48e194b commit c0c30b6

File tree

4 files changed

+9
-12
lines changed

4 files changed

+9
-12
lines changed

docs/next/en-US/reference/state/global.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Global State
22

3-
As you've seen, Perseus has full support for reactive state in templates, but what about state that's not associated with any template? The usual example is something like dark mode, which the user might manually disable. In most JavaScript frameworks, you'd bring in some bloated state management system to handle this, but Perseus has global state built in. To declare it, you create a `GlobalStateCreator`, which will be used to generate some state, and then that'll be made reactive and passed to your templates as their second argument (if they have one, and you'll have to use the `#[template_rx(...)]` macro).
3+
As you've seen, Perseus has full support for reactive state in templates, but what about state that's not associated with any template? The usual example is something like dark mode, which the user might manually disable. In most JavaScript frameworks, you'd bring in some bloated state management system to handle this, but Perseus has global state built in. To declare it, you create a `GlobalStateCreator`, which will be used to generate some state, and then that'll be made reactive and passed to your templates as their second argument (if they have one, and you'll have to use the `#[template_rx]` macro).
44

55
The essence of global state is that you can generate it at build-time (though with something like setting dark mode, you'll probably want to ignore whatever was set at build time until you know the browser's preferences) and access it seamlessly from any template. Just like usual [reactive state](:reference/state/rx), you can make it reactive with `#[make_rx(...)]`, and you essentially get app-wide MVC with just a few lines of code (and no extra dependencies, all this is completely built into Perseus).
66

@@ -37,4 +37,4 @@ Finally, you can use it like so (note the second argument to `index_page`):
3737

3838
## Potential Issues
3939

40-
Global state has a quirk that shouldn't be an issue for most, but that can be very helpful to know about if you start to dig into the internals of Perseus. Global state is passed down from the server as a window-level JS variable (as with template state), but it doesn't immediately get deserialized and registered, it's loaded lazily. So, if the user loads fifty templates that don't access global state, your app won't initialize the global state. But, the moment you take it as an argument to a template, it will be set up. This means that, while you can access the global state through the render context (with `perseus::get_render_ctx!()`), you shouldn't do this except in templates that already take the global state as an argument. It may seem tempting to assume that the user has already gone to another page which has set up global state, but no matter how the flow of your app works, you mustn't assume this because of [state freezing](:reference/state/freezing), which can break such flows. Basically, don't access the global state through the render context, you almost never need to and it may be wrong. Trust in `#[template_rx(...)]`.
40+
Global state has a quirk that shouldn't be an issue for most, but that can be very helpful to know about if you start to dig into the internals of Perseus. Global state is passed down from the server as a window-level JS variable (as with template state), but it doesn't immediately get deserialized and registered, it's loaded lazily. So, if the user loads fifty templates that don't access global state, your app won't initialize the global state. But, the moment you take it as an argument to a template, it will be set up. This means that, while you can access the global state through the render context (with `perseus::get_render_ctx!()`), you shouldn't do this except in templates that already take the global state as an argument. It may seem tempting to assume that the user has already gone to another page which has set up global state, but no matter how the flow of your app works, you mustn't assume this because of [state freezing](:reference/state/freezing), which can break such flows. Basically, don't access the global state through the render context, you almost never need to and it may be wrong. Trust in `#[template_rx]`.

docs/next/en-US/reference/state/rx.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ To use this new platform, just annotate a state `struct` with `#[perseus::make_r
88

99
*Note: Sycamore has a proposal to support fine-grained reactivity like this through observers, which will supersede this when they're released, and they'll make all this even faster! Right now, everything has to be cloned unfortunately.*
1010

11-
Once you've got some reactive versions of your state `struct`s ready, you should generate the unreactive versions as usual in functions like `get_build_state()`, but then set the first argument on your template function to the reactive version (e.g. `IndexStateRx` rather than `IndexState`). This requires Perseus to convert between the unreactive and reactive versions in the background, which you can enable by changing the old `#[template(...)]` (used in the old documentation/tutorials) to `#[template_rx(...)]` and removing the Sycamore `#[component]` annotation (this is added automatically by `#[template_rx(...)]`). Behind the scenes, you've just enabled the world's most powerful state platform, and not only will your state be made reactive for you, it will be added to the *page state store*, a global store that enables Perseus to cache the state of a page. So, if your users start filling out forms on page 1 and then go to page 2, and then come back to page 1, their forms will be just how they left them. (Not sure about you, but it feels to us like it's about time this was the default on the web!)
11+
Once you've got some reactive versions of your state `struct`s ready, you should generate the unreactive versions as usual in functions like `get_build_state()`, but then set the first argument on your template function to the reactive version (e.g. `IndexStateRx` rather than `IndexState`). This requires Perseus to convert between the unreactive and reactive versions in the background, which you can enable by changing the old `#[template(...)]` (used in the old documentation/tutorials) to `#[template_rx]` and removing the Sycamore `#[component]` annotation (this is added automatically by `#[template_rx]`). Behind the scenes, you've just enabled the world's most powerful state platform, and not only will your state be made reactive for you, it will be added to the *page state store*, a global store that enables Perseus to cache the state of a page. So, if your users start filling out forms on page 1 and then go to page 2, and then come back to page 1, their forms will be just how they left them. (Not sure about you, but it feels to us like it's about time this was the default on the web!)
1212

1313
*Side note: if you think this behavior is horrific, you can still use the old `#[template(...)] macro, and we have no plans to deprecate it. Perseus' original unreactive state system worked very well, and there are still plenty of use cases where you may not want all this newfangled reactive state nonsense (like completely static blogs).*
1414

docs/next/en-US/tutorials/second-app.md

+4-4
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ Note that we also use the `#[perseus::make_rx(IndexPageStateRx)]` macro here to
8787

8888
### `index_page()`
8989

90-
This is the actual component that will render a user interface for your page. Perseus lets you provide a *template function* like this as a simple Rust function that takes in your page's state and produces a Sycamore `View<G>` (again, `G` is ambient here because of the proc macro). However, there's *a lot* of work that goes on behind the scenes to make your state reactive, register it with Perseus, manage [global state](:reference/state/global), and set up a Sycamore component that's usable by the rest of the Perseus code. This is all done with one of two attribute macros: `#[perseus::template(...)]` or `#[perseus::template_rx(...)]`. In previous versions of Perseus, you'd use the former, which would give you an unreactive instance of your state (in our case, `IndexPageState`). However, since v0.3.3, it's recommended to use the latter, which gives you a reactive version (in our case, `IndexPageStateRx`) and can manage more advanced features of Perseus' [reactive state platform](:reference/state/rx), so that's what we use here.
90+
This is the actual component that will render a user interface for your page. Perseus lets you provide a *template function* like this as a simple Rust function that takes in your page's state and produces a Sycamore `View<G>` (again, `G` is ambient here because of the proc macro). However, there's *a lot* of work that goes on behind the scenes to make your state reactive, register it with Perseus, manage [global state](:reference/state/global), and set up a Sycamore component that's usable by the rest of the Perseus code. This is all done with one of two attribute macros: `#[perseus::template(...)]` or `#[perseus::template_rx]`. In previous versions of Perseus, you'd use the former, which would give you an unreactive instance of your state (in our case, `IndexPageState`). However, since v0.3.3, it's recommended to use the latter, which gives you a reactive version (in our case, `IndexPageStateRx`) and can manage more advanced features of Perseus' [reactive state platform](:reference/state/rx), so that's what we use here. Also, `template_rx` manages things like Sycamore components internally for you, minimising the amount of code you actually have to write.
9191

9292
Note that `index_page()` takes `IndexPageStateRx` as an argument, which it can then access in the `view!`. This is Sycamore's interpolation system, which you can read about [here](https://sycamore-rs.netlify.app/docs/basics/template), but all you need to know is that it's basically seamless and works exactly as you'd expect (remember though that, because we're using the `template_rx` macro, we have to use a reactive state `struct`, which we generate with the `make_rx` macro, so all our fields are wrapped in `Signal`s, which is why we use `.get()`).
9393

@@ -113,11 +113,11 @@ Perseus' templating system is extremely versatile, and here we're using it to de
113113

114114
#### `.template()`
115115

116-
This function is what Perseus will call when it wants to render your template (which it does more often than you might think). If you've used the `#[perseus::template_rx(...)]` or `#[perseus::template(...)]` macro on `index_page()`, you can provide `index_page` directly here, but it can be useful to understand what that macro is doing.
116+
This function is what Perseus will call when it wants to render your template (which it does more often than you might think). If you've used the `#[perseus::template_rx]` or `#[perseus::template(...)]` macro on `index_page()`, you can provide `index_page` directly here, but it can be useful to understand what that macro is doing.
117117

118-
Behind the scenes, that macro transforms your `index_page()` function to take properties as an `Option<String>` instead of as `IndexPageState`, because Perseus actually passes your properties around internally as `String`s. At first, this might seem weird, but it avoids a few common problems that would increase your final Wasm binary size and make your website take a very long time to load. Interestingly, it's actually also more performant to use `String`s everywhere, because we need to perform that conversion anyway when we send your properties to a user's browser. In addition, the `#[perseus::template_rx(...)]` macro will manage setting up and interacting with the more complex features of Perseus' [reactive state platform](:reference/state/rx).
118+
Behind the scenes, that macro transforms your `index_page()` function to take properties as an `Option<String>` instead of as `IndexPageState`, because Perseus actually passes your properties around internally as `String`s. At first, this might seem weird, but it avoids a few common problems that would increase your final Wasm binary size and make your website take a very long time to load. Interestingly, it's actually also more performant to use `String`s everywhere, because we need to perform that conversion anyway when we send your properties to a user's browser. In addition, the `#[perseus::template_rx]` macro will manage setting up and interacting with the more complex features of Perseus' [reactive state platform](:reference/state/rx).
119119

120-
If that all went over your head, don't worry, that's just what Perseus does behind the scenes, and what you used to have to do by hand! The `#[perseus::template(...)]`/`#[perseus::template_rx()]` macros do all that for you.
120+
If that all went over your head, don't worry, that's just what Perseus does behind the scenes, and what you used to have to do by hand! The `#[perseus::template(...)]`/`#[perseus::template_rx]` macros do all that for you.
121121

122122
#### `.head()`
123123

packages/perseus-macro/src/lib.rs

+2-5
Original file line numberDiff line numberDiff line change
@@ -59,17 +59,14 @@ pub fn template(args: TokenStream, input: TokenStream) -> TokenStream {
5959
}
6060

6161
/// The new version of `#[template]` designed for reactive state. This can interface automatically with global state, and will automatically provide Sycamore `#[component]` annotations. To
62-
/// use this, you'll need to provide your component's name (e.g. `IndexPage`) as `#[template_rx(IndexPage)]` (just like with the old macro). You can also provide a custom type parameter
63-
/// name to use for your component (defaults to `G`) as the second argument.
62+
/// use this, you don't need to provide anything other than an optional custom type parameter letter (by default, `G` will be used). Unlike with the original macro, this will automatically
63+
/// handle component names internally.
6464
///
6565
/// The first argument your template function can take is state generated for it (e.g. by the *build state* strategy), but the reactive version (created with `#[make_rx]` usually). From this,
6666
/// Perseus can infer the other required types and automatically make your state reactive for you.
6767
///
6868
/// The second argument your template function can take is a global state generated with the `GlobalStateCreator`. You should also provide the reactive type here, and Perseus will do all the
6969
/// rest in the background.
70-
///
71-
/// **Warning:** this macro is currently exempt from semantic versioning, and breaking changes may be introduced here at any time! If you want stability, use the `#[template]` macro (but you won't
72-
/// get access to Perseus' reactive state platform).
7370
#[proc_macro_attribute]
7471
pub fn template_rx(args: TokenStream, input: TokenStream) -> TokenStream {
7572
let parsed = syn::parse_macro_input!(input as template_rx::TemplateFn);

0 commit comments

Comments
 (0)