Document props and component macro (#2522)

* document prop attributes

* document children props

* fix children doc test
This commit is contained in:
Evan Almloff 2024-06-19 01:06:54 +02:00 committed by GitHub
parent f042e0029c
commit 3a4860add4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 861 additions and 229 deletions

View file

@ -0,0 +1,323 @@
# Component
The component macro turns a function with arguments that are [`Clone`] and [`PartialEq`] into a component. This is the recommended way of creating most components. If you want more fine grained control over how the overall prop struct implements the `Properties` trait, you can use an explicit props struct with the [`Props`] derive macro instead.
## Arguments
- `no_case_check` - Doesn't enforce `PascalCase` on your component names.
**This will be removed/deprecated in a future update in favor of a more complete Clippy-backed linting system.**
The reasoning behind this is that Clippy allows more robust and powerful lints, whereas
macros are extremely limited.
## Features
This attribute:
- Enforces that your component uses `PascalCase` or `snake_case` with at least one underscore.
- Automatically creates a prop struct for your component if the function has arguments.
- Verifies the function signature is valid as a component.
## Examples
- Without props:
```rust, no_run
# use dioxus::prelude::*;
#[component]
fn GreetBob() -> Element {
rsx! { "hello, bob" }
}
```
- With props:
```rust, no_run
# use dioxus::prelude::*;
#[component]
fn GreetBob(bob: String) -> Element {
rsx! { "hello, {bob}" }
}
```
## Prop Modifiers
You can use the `#[props()]` attribute to modify the behavior of the props the component macro creates:
- [`#[props(default)]`](#default-props) - Makes the field optional in the component and uses the default value if it is not set when creating the component.
- [`#[props(!optional)]`](#optional-props) - Makes a field with the type `Option<T>` required.
- [`#[props(into)]`](#converting-props) - Converts a field into the correct type by using the [`Into`] trait.
- [`#[props(extends = GlobalAttributes)]`](#extending-elements) - Extends the props with all the attributes from an element or the global element attributes.
Props also act slightly differently when used with:
- [`Option<T>`](#optional-props) - The field is automatically optional with a default value of `None`.
- [`ReadOnlySignal<T>`](#reactive-props) - The props macro will automatically convert `T` into `ReadOnlySignal<T>` when it is passed as a prop.
- [`String`](#formatted-props) - The props macro will accept formatted strings for any prop field with the type `String`.
- [`children`](#children-props) - The props macro will accept child elements if you include the `children` prop.
### Default Props
The `default` attribute lets you define a default value for a field if it isn't set when creating the component
```rust, no_run
# use dioxus::prelude::*;
#[component]
fn Button(
// The default attributes makes your field optional in the component and uses the default value if it is not set.
#[props(default)]
text: String,
// You can also set an explicit default value instead of using the `Default` implementation.
#[props(default = "red".to_string())]
color: String,
) -> Element {
rsx! {
button {
color: color,
"{text}"
}
}
}
rsx! {
// You can skip setting props that have a default value when you use the component.
Button {}
};
```
### Optional Props
When defining a component, you may want to make a prop optional without defining an explicit default value. Any fields with the type `Option<T>` are automatically optional with a default value of `None`.
```rust, no_run
# use dioxus::prelude::*;
#[component]
fn Button(
// Since the `text` field is optional, you don't need to set it when you use the component.
text: Option<String>,
) -> Element {
rsx! {
button { {text.unwrap_or("button".to_string())} }
}
}
rsx! {
Button {}
};
```
If you want to make your `Option<T>` field required, you can use the `!optional` attribute:
```rust, no_run
# use dioxus::prelude::*;
#[component]
fn Button(
// You can use the `!optional` attribute on a field with the type `Option<T>` to make it required.
#[props(!optional)]
text: Option<String>,
) -> Element {
rsx! {
button { {text.unwrap_or("button".to_string())} }
}
}
rsx! {
Button {
text: None
}
};
```
### Converting Props
You can automatically convert a field into the correct type by using the `into` attribute. Any type you pass into the field will be converted with the [`Into`] trait:
```rust, no_run
# use dioxus::prelude::*;
#[component]
fn Button(
// You can use the `into` attribute on a field to convert types you pass in with the Into trait.
#[props(into)]
number: u64,
) -> Element {
rsx! {
button { "{number}" }
}
}
rsx! {
Button {
// Because we used the into attribute, we can pass in any type that implements Into<u64>
number: 10u8
}
};
```
### Formatted Props
You can use formatted strings in attributes just like you would in an element. Any prop field with the type `String` can accept a formatted string:
```rust, no_run
# use dioxus::prelude::*;
#[component]
fn Button(text: String,) -> Element {
rsx! {
button { "{text}" }
}
}
let name = "Bob";
rsx! {
Button {
// You can use formatted strings in props that accept String just like you would in an element.
text: "Hello {name}!"
}
};
```
### Children Props
Rather than passing the RSX through a regular prop, you may wish to accept children similarly to how elements can have children. The "magic" children prop lets you achieve this:
```rust, no_run
# use dioxus::prelude::*;
#[component]
fn Clickable(
href: String,
children: Element,
) -> Element {
rsx! {
a {
href: "{href}",
class: "fancy-button",
{children}
}
}
}
```
This makes providing children to the component much simpler: simply put the RSX inside the {} brackets:
```rust, no_run
# use dioxus::prelude::*;
# #[component]
# fn Clickable(
# href: String,
# children: Element,
# ) -> Element {
# rsx! {
# a {
# href: "{href}",
# class: "fancy-button",
# {children}
# }
# }
# }
rsx! {
Clickable {
href: "https://www.youtube.com/watch?v=C-M2hs3sXGo",
"How to "
i { "not" }
" be seen"
}
};
```
### Reactive Props
In dioxus, when a prop changes, the component will rerun with the new value to update the UI. For example, if count changes from 0 to 1, this component will rerun and update the UI to show "Count: 1":
```rust, no_run
# use dioxus::prelude::*;
#[component]
fn Counter(count: i32) -> Element {
rsx! {
div {
"Count: {count}"
}
}
}
```
Generally, just rerunning the component is enough to update the UI. However, if you use your prop inside reactive hooks like `use_memo` or `use_resource`, you may also want to restart those hooks when the prop changes:
```rust, no_run
# use dioxus::prelude::*;
#[component]
fn Counter(count: i32) -> Element {
// We can use a memo to calculate the doubled count. Since this memo will only be created the first time the component is run and `count` is not reactive, it will never update when `count` changes.
let doubled_count = use_memo(move || count * 2);
rsx! {
div {
"Count: {count}"
"Doubled Count: {doubled_count}"
}
}
}
```
To fix this issue you can either:
1. Make the prop reactive by wrapping it in `ReadOnlySignal` (recommended):
`ReadOnlySignal` is a `Copy` reactive value. Dioxus will automatically convert any value into a `ReadOnlySignal` when it is passed as a prop.
```rust, no_run
# use dioxus::prelude::*;
#[component]
fn Counter(count: ReadOnlySignal<i32>) -> Element {
// Since we made count reactive, the memo will automatically rerun when count changes.
let doubled_count = use_memo(move || count() * 2);
rsx! {
div {
"Count: {count}"
"Doubled Count: {doubled_count}"
}
}
}
```
2. Explicitly add the prop as a dependency to the reactive hook with [`use_reactive`](https://docs.rs/dioxus-hooks/latest/dioxus_hooks/macro.use_reactive.html):
```rust, no_run
# use dioxus::prelude::*;
#[component]
fn Counter(count: i32) -> Element {
// We can add the count prop as an explicit dependency to every reactive hook that uses it with use_reactive.
// The use_reactive macro takes a closure with explicit dependencies as its argument.
let doubled_count = use_memo(use_reactive!(|count| count * 2));
rsx! {
div {
"Count: {count}"
"Doubled Count: {doubled_count}"
}
}
}
```
### Extending Elements
The `extends` attribute lets you extend your props with all the attributes from an element or the global element attributes.
```rust, no_run
# use dioxus::prelude::*;
#[component]
fn Button(
// You can use the `extends` attribute on a field with the type `Vec<Attribute>` to extend the props with all the attributes from an element or the global element attributes.
#[props(extends = GlobalAttributes)]
attributes: Vec<Attribute>,
) -> Element {
rsx! {
// Instead of copying over every single attribute, we can just spread the attributes from the props into the button.
button { ..attributes, "button" }
}
}
rsx! {
// Since we extend global attributes, you can use any attribute that would normally appear on the button element.
Button {
width: "10px",
height: "10px",
color: "red",
}
};
```

View file

@ -0,0 +1,339 @@
# Props
The props derive macro allows you to define what props your component accepts and how to accept those props. Every component must either accept no arguments or accept a single argument that implements the `Properties` trait.
> Note: You should generally prefer using the `#[component]` macro instead of the `#[derive(Props)]` macro with explicit props. The `#[component]` macro will automatically generate the props struct for you and perform extra checks to ensure that your component is valid.
## Example
```rust, no_run
# use dioxus::prelude::*;
#[derive(Props, PartialEq, Clone)]
struct ButtonProps {
/// The text of the button
text: String,
/// The color of the button
color: String,
}
fn Button(props: ButtonProps) -> Element {
rsx! {
button {
color: props.color,
"{props.text}"
}
}
}
rsx! {
// Any fields you defined on the props struct will be turned into props for the component.
Button {
text: "Click me!",
color: "red",
}
};
```
## Prop Modifiers
You can use the `#[props()]` attribute to modify the behavior of the props derive macro:
- [`#[props(default)]`](#default-props) - Makes the field optional in the component and uses the default value if it is not set when creating the component.
- [`#[props(!optional)]`](#optional-props) - Makes a field with the type `Option<T>` required.
- [`#[props(into)]`](#converting-props) - Converts a field into the correct type by using the [`Into`] trait.
- [`#[props(extends = GlobalAttributes)]`](#extending-elements) - Extends the props with all the attributes from an element or the global element attributes.
Props also act slightly differently when used with:
- [`Option<T>`](#optional-props) - The field is automatically optional with a default value of `None`.
- [`ReadOnlySignal<T>`](#reactive-props) - The props macro will automatically convert `T` into `ReadOnlySignal<T>` when it is passed as a prop.
- [`String`](#formatted-props) - The props macro will accept formatted strings for any prop field with the type `String`.
- [`children`](#children-props) - The props macro will accept child elements if you include the `children` prop.
### Default Props
The `default` attribute lets you define a default value for a field if it isn't set when creating the component
```rust, no_run
# use dioxus::prelude::*;
#[derive(Props, PartialEq, Clone)]
struct ButtonProps {
// The default attributes makes your field optional in the component and uses the default value if it is not set.
#[props(default)]
text: String,
/// You can also set an explicit default value instead of using the `Default` implementation.
#[props(default = "red".to_string())]
color: String,
}
fn Button(props: ButtonProps) -> Element {
rsx! {
button {
color: props.color,
"{props.text}"
}
}
}
rsx! {
// You can skip setting props that have a default value when you use the component.
Button {}
};
```
### Optional Props
When defining props, you may want to make a prop optional without defining an explicit default value. Any fields with the type `Option<T>` are automatically optional with a default value of `None`.
```rust, no_run
# use dioxus::prelude::*;
#[derive(Props, PartialEq, Clone)]
struct ButtonProps {
// Since the `text` field is optional, you don't need to set it when you use the component.
text: Option<String>,
}
fn Button(props: ButtonProps) -> Element {
rsx! {
button { {props.text.unwrap_or("button".to_string())} }
}
}
rsx! {
Button {}
};
```
If you want to make your `Option<T>` field required, you can use the `!optional` attribute:
```rust, no_run
# use dioxus::prelude::*;
#[derive(Props, PartialEq, Clone)]
struct ButtonProps {
/// You can use the `!optional` attribute on a field with the type `Option<T>` to make it required.
#[props(!optional)]
text: Option<String>,
}
fn Button(props: ButtonProps) -> Element {
rsx! {
button { {props.text.unwrap_or("button".to_string())} }
}
}
rsx! {
Button {
text: None
}
};
```
### Converting Props
You can automatically convert a field into the correct type by using the `into` attribute. Any type you pass into the field will be converted with the [`Into`] trait:
```rust, no_run
# use dioxus::prelude::*;
#[derive(Props, PartialEq, Clone)]
struct ButtonProps {
/// You can use the `into` attribute on a field to convert types you pass in with the Into trait.
#[props(into)]
number: u64,
}
fn Button(props: ButtonProps) -> Element {
rsx! {
button { "{props.number}" }
}
}
rsx! {
Button {
// Because we used the into attribute, we can pass in any type that implements Into<u64>
number: 10u8
}
};
```
### Formatted Props
You can use formatted strings in attributes just like you would in an element. Any prop field with the type `String` can accept a formatted string:
```rust, no_run
# use dioxus::prelude::*;
#[derive(Props, PartialEq, Clone)]
struct ButtonProps {
text: String,
}
fn Button(props: ButtonProps) -> Element {
rsx! {
button { "{props.text}" }
}
}
let name = "Bob";
rsx! {
Button {
// You can use formatted strings in props that accept String just like you would in an element.
text: "Hello {name}!"
}
};
```
### Children Props
Rather than passing the RSX through a regular prop, you may wish to accept children similarly to how elements can have children. The "magic" children prop lets you achieve this:
```rust, no_run
# use dioxus::prelude::*;
#[derive(PartialEq, Clone, Props)]
struct ClickableProps {
href: String,
children: Element,
}
fn Clickable(props: ClickableProps) -> Element {
rsx! {
a {
href: "{props.href}",
class: "fancy-button",
{props.children}
}
}
}
```
This makes providing children to the component much simpler: simply put the RSX inside the {} brackets:
```rust, no_run
# use dioxus::prelude::*;
# #[derive(PartialEq, Clone, Props)]
# struct ClickableProps {
# href: String,
# children: Element,
# }
#
# fn Clickable(props: ClickableProps) -> Element {
# rsx! {
# a {
# href: "{props.href}",
# class: "fancy-button",
# {props.children}
# }
# }
# }
rsx! {
Clickable {
href: "https://www.youtube.com/watch?v=C-M2hs3sXGo",
"How to "
i { "not" }
" be seen"
}
};
```
### Reactive Props
In dioxus, when a prop changes, the component will rerun with the new value to update the UI. For example, if count changes from 0 to 1, this component will rerun and update the UI to show "Count: 1":
```rust, no_run
# use dioxus::prelude::*;
#[component]
fn Counter(count: i32) -> Element {
rsx! {
div {
"Count: {count}"
}
}
}
```
Generally, just rerunning the component is enough to update the UI. However, if you use your prop inside reactive hooks like `use_memo` or `use_resource`, you may also want to restart those hooks when the prop changes:
```rust, no_run
# use dioxus::prelude::*;
#[component]
fn Counter(count: i32) -> Element {
// We can use a memo to calculate the doubled count. Since this memo will only be created the first time the component is run and `count` is not reactive, it will never update when `count` changes.
let doubled_count = use_memo(move || count * 2);
rsx! {
div {
"Count: {count}"
"Doubled Count: {doubled_count}"
}
}
}
```
To fix this issue you can either:
1. Make the prop reactive by wrapping it in `ReadOnlySignal` (recommended):
`ReadOnlySignal` is a `Copy` reactive value. Dioxus will automatically convert any value into a `ReadOnlySignal` when it is passed as a prop.
```rust, no_run
# use dioxus::prelude::*;
#[component]
fn Counter(count: ReadOnlySignal<i32>) -> Element {
// Since we made count reactive, the memo will automatically rerun when count changes.
let doubled_count = use_memo(move || count() * 2);
rsx! {
div {
"Count: {count}"
"Doubled Count: {doubled_count}"
}
}
}
```
2. Explicitly add the prop as a dependency to the reactive hook with [`use_reactive`](https://docs.rs/dioxus-hooks/latest/dioxus_hooks/macro.use_reactive.html):
```rust, no_run
# use dioxus::prelude::*;
#[component]
fn Counter(count: i32) -> Element {
// We can add the count prop as an explicit dependency to every reactive hook that uses it with use_reactive.
// The use_reactive macro takes a closure with explicit dependencies as its argument.
let doubled_count = use_memo(use_reactive!(|count| count * 2));
rsx! {
div {
"Count: {count}"
"Doubled Count: {doubled_count}"
}
}
}
```
### Extending Elements
The `extends` attribute lets you extend your props with all the attributes from an element or the global element attributes.
```rust, no_run
# use dioxus::prelude::*;
#[derive(Props, PartialEq, Clone)]
struct ButtonProps {
/// You can use the `extends` attribute on a field with the type `Vec<Attribute>` to extend the props with all the attributes from an element or the global element attributes.
#[props(extends = GlobalAttributes)]
attributes: Vec<Attribute>,
}
#[component]
fn Button(props: ButtonProps) -> Element {
rsx! {
// Instead of copying over every single attribute, we can just spread the attributes from the props into the button.
button { ..props.attributes, "button" }
}
}
rsx! {
// Since we extend global attributes, you can use any attribute that would normally appear on the button element.
Button {
width: "10px",
height: "10px",
color: "red",
}
};
```

View file

@ -0,0 +1,185 @@
The rsx! macro makes it easy for developers to write jsx-style markup in their components.
## Elements
You can render elements with rsx! with the element name and then braces surrounding the attributes and children.
```rust, no_run
# use dioxus::prelude::*;
rsx! {
div {
div {}
}
};
```
<details>
<summary>Web Components</summary>
Dioxus will automatically render any elements with `-` as a untyped web component:
```rust, no_run
# use dioxus::prelude::*;
rsx! {
div-component {
div {}
}
};
```
You can wrap your web component in a custom component to add type checking:
```rust, no_run
# use dioxus::prelude::*;
#[component]
fn MyDivComponent(width: i64) -> Element {
rsx! {
div-component {
"width": width
}
}
}
```
</details>
## Attributes
You can add attributes to any element inside the braces. Attributes are key-value pairs separated by a colon.
```rust, no_run
# use dioxus::prelude::*;
let width = 100;
rsx! {
div {
// Set the class attribute to "my-class"
class: "my-class",
// attribute strings are automatically formatted with the format macro
width: "{width}px",
}
};
```
### Optional Attributes
You can include optional attributes with an unterminated if statement as the value of the attribute:
```rust, no_run
# use dioxus::prelude::*;
# let first_boolean = true;
# let second_boolean = false;
rsx! {
div {
// Set the class attribute to "my-class" if true
class: if first_boolean {
"my-class"
},
// Set the class attribute to "my-other-class" if false
class: if second_boolean {
"my-other-class"
}
}
};
```
### Raw Attributes
Dioxus defaults to attributes that are type checked as html. If you want to include an attribute that is not included in the html spec, you can use the `raw` attribute surrounded by quotes:
```rust, no_run
# use dioxus::prelude::*;
rsx! {
div {
// Set the data-count attribute to "1"
"data-count": "1"
}
};
```
## Text
You can include text in your markup as a string literal:
```rust, no_run
# use dioxus::prelude::*;
let name = "World";
rsx! {
div {
"Hello World"
// Just like attributes, you can included formatted segments inside your text
"Hello {name}"
}
};
```
## Components
You can render any [`macro@crate::component`]s you created inside your markup just like elements. Components must either start with a capital letter or contain a `_` character.
```rust, no_run
# use dioxus::prelude::*;
#[component]
fn HelloWorld() -> Element {
rsx! { "hello world!" }
}
rsx! {
div {
HelloWorld {}
}
};
```
## If statements
You can use if statements to conditionally render children. The body of the for if statement is parsed as rsx markup:
```rust, no_run
# use dioxus::prelude::*;
let first_boolean = true;
let second_boolean = false;
rsx! {
if first_boolean {
div {
"first"
}
}
if second_boolean {
"second"
}
};
```
## For loops
You can also use for loops to iterate over a collection of items. The body of the for loop is parsed as rsx markup:
```rust, no_run
# use dioxus::prelude::*;
let numbers = vec![1, 2, 3];
rsx! {
for number in numbers {
div {
"{number}"
}
}
};
```
## Raw Expressions
You can include raw expressions inside your markup inside curly braces. Your expression must implement the [`IntoDynNode`](https://docs.rs/dioxus-core/latest/dioxus_core/trait.IntoDynNode.html) trait:
```rust, no_run
# use dioxus::prelude::*;
let name = "World";
rsx! {
div {
// Text can be converted into a dynamic node in rsx
{name}
}
// Iterators can also be converted into dynamic nodes
{(0..10).map(|n| n * n).map(|number| rsx! { div { "{number}" } })}
};
```

View file

@ -13,6 +13,13 @@ mod utils;
use dioxus_rsx as rsx;
/// Format a string with inline rust expressions. [`format_args_f!`] is very similar to [`format_args`], but it allows you to use arbitrary rust expressions inside braces instead of just variables:
///
/// ```rust,no_run
/// # use dioxus::prelude::*;
/// let formatted_with_variables = format_args!("{} + {} = {}", 1, 2, 1 + 2);
/// let formatted_with_inline_expressions = format_args_f!("{1} + {2} = {1 + 2}");
/// ```
#[proc_macro]
pub fn format_args_f(input: TokenStream) -> TokenStream {
use rsx::*;
@ -21,6 +28,7 @@ pub fn format_args_f(input: TokenStream) -> TokenStream {
.into()
}
#[doc = include_str!("../docs/props.md")]
#[proc_macro_derive(Props, attributes(props))]
pub fn derive_typed_builder(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as syn::DeriveInput);
@ -30,192 +38,7 @@ pub fn derive_typed_builder(input: TokenStream) -> TokenStream {
}
}
/// The rsx! macro makes it easy for developers to write jsx-style markup in their components.
///
/// ## Elements
///
/// You can render elements with rsx! with the element name and then braces surrounding the attributes and children.
///
/// ```rust, no_run
/// # use dioxus::prelude::*;
/// rsx! {
/// div {
/// div {}
/// }
/// };
/// ```
///
/// <details>
/// <summary>Web Components</summary>
///
///
/// Dioxus will automatically render any elements with `-` as a untyped web component:
///
/// ```rust, no_run
/// # use dioxus::prelude::*;
/// rsx! {
/// div-component {
/// div {}
/// }
/// };
/// ```
///
/// You can wrap your web component in a custom component to add type checking:
/// ```rust, no_run
/// # use dioxus::prelude::*;
/// #[component]
/// fn MyDivComponent(width: i64) -> Element {
/// rsx! {
/// div-component {
/// "width": width
/// }
/// }
/// }
/// ```
///
///
/// </details>
///
/// ## Attributes
///
/// You can add attributes to any element inside the braces. Attributes are key-value pairs separated by a colon.
///
/// ```rust, no_run
/// # use dioxus::prelude::*;
/// let width = 100;
/// rsx! {
/// div {
/// // Set the class attribute to "my-class"
/// class: "my-class",
/// // attribute strings are automatically formatted with the format macro
/// width: "{width}px",
/// }
/// };
/// ```
///
/// ### Optional Attributes
///
/// You can include optional attributes with an unterminated if statement as the value of the attribute:
///
/// ```rust, no_run
/// # use dioxus::prelude::*;
/// # let first_boolean = true;
/// # let second_boolean = false;
/// rsx! {
/// div {
/// // Set the class attribute to "my-class" if true
/// class: if first_boolean {
/// "my-class"
/// },
/// // Set the class attribute to "my-other-class" if false
/// class: if second_boolean {
/// "my-other-class"
/// }
/// }
/// };
/// ```
///
/// ### Raw Attributes
///
/// Dioxus defaults to attributes that are type checked as html. If you want to include an attribute that is not included in the html spec, you can use the `raw` attribute surrounded by quotes:
///
/// ```rust, no_run
/// # use dioxus::prelude::*;
/// rsx! {
/// div {
/// // Set the data-count attribute to "1"
/// "data-count": "1"
/// }
/// };
/// ```
///
/// ## Text
///
/// You can include text in your markup as a string literal:
///
/// ```rust, no_run
/// # use dioxus::prelude::*;
/// let name = "World";
/// rsx! {
/// div {
/// "Hello World"
/// // Just like attributes, you can included formatted segments inside your text
/// "Hello {name}"
/// }
/// };
/// ```
///
/// ## Components
///
/// You can render any [`macro@crate::component`]s you created inside your markup just like elements. Components must either start with a capital letter or contain a `_` character.
///
/// ```rust, no_run
/// # use dioxus::prelude::*;
/// #[component]
/// fn HelloWorld() -> Element {
/// rsx! { "hello world!" }
/// }
///
/// rsx! {
/// div {
/// HelloWorld {}
/// }
/// };
/// ```
///
/// ## If statements
///
/// You can use if statements to conditionally render children. The body of the for if statement is parsed as rsx markup:
///
/// ```rust, no_run
/// # use dioxus::prelude::*;
/// let first_boolean = true;
/// let second_boolean = false;
/// rsx! {
/// if first_boolean {
/// div {
/// "first"
/// }
/// }
///
/// if second_boolean {
/// "second"
/// }
/// };
/// ```
///
/// ## For loops
///
/// You can also use for loops to iterate over a collection of items. The body of the for loop is parsed as rsx markup:
///
/// ```rust, no_run
/// # use dioxus::prelude::*;
/// let numbers = vec![1, 2, 3];
/// rsx! {
/// for number in numbers {
/// div {
/// "{number}"
/// }
/// }
/// };
/// ```
///
/// ## Raw Expressions
///
/// You can include raw expressions inside your markup inside curly braces. Your expression must implement the [`IntoDynNode`](https://docs.rs/dioxus-core/latest/dioxus_core/trait.IntoDynNode.html) trait:
///
/// ```rust, no_run
/// # use dioxus::prelude::*;
/// let name = "World";
/// rsx! {
/// div {
/// // Text can be converted into a dynamic node in rsx
/// {name}
/// }
/// // Iterators can also be converted into dynamic nodes
/// {(0..10).map(|n| n * n).map(|number| rsx! { div { "{number}" } })}
/// };
/// ```
#[doc = include_str!("../docs/rsx.md")]
#[proc_macro]
pub fn rsx(tokens: TokenStream) -> TokenStream {
match syn::parse::<rsx::CallBody>(tokens) {
@ -231,45 +54,7 @@ pub fn render(tokens: TokenStream) -> TokenStream {
rsx(tokens)
}
/// Streamlines component creation.
/// This is the recommended way of creating components,
/// though you might want lower-level control with more advanced uses.
///
/// # Arguments
/// * `no_case_check` - Doesn't enforce `PascalCase` on your component names.
/// **This will be removed/deprecated in a future update in favor of a more complete Clippy-backed linting system.**
/// The reasoning behind this is that Clippy allows more robust and powerful lints, whereas
/// macros are extremely limited.
///
/// # Features
/// This attribute:
/// * Enforces that your component uses `PascalCase`.
/// No warnings are generated for the `PascalCase`
/// function name, but everything else will still raise a warning if it's incorrectly `PascalCase`.
/// Does not disable warnings anywhere else, so if you, for example,
/// accidentally don't use `snake_case`
/// for a variable name in the function, the compiler will still warn you.
/// * Automatically uses `#[inline_props]` if there's more than 1 parameter in the function.
/// * Verifies the validity of your component.
///
/// # Examples
/// * Without props:
/// ```rust, no_run
/// # use dioxus::prelude::*;
/// #[component]
/// fn GreetBob() -> Element {
/// rsx! { "hello, bob" }
/// }
/// ```
///
/// * With props:
/// ```rust, no_run
/// # use dioxus::prelude::*;
/// #[component]
/// fn GreetBob(bob: String) -> Element {
/// rsx! { "hello, {bob}" }
/// }
/// ```
#[doc = include_str!("../docs/component.md")]
#[proc_macro_attribute]
pub fn component(_args: TokenStream, input: TokenStream) -> TokenStream {
parse_macro_input!(input as ComponentBody)

View file

@ -270,7 +270,7 @@ pub fn schedule_update_any() -> Arc<dyn Fn(ScopeId) + Send + Sync> {
/// Creates a callback that will be run before the component is removed.
/// This can be used to clean up side effects from the component
/// (created with [`use_effect`](crate::use_effect)).
/// (created with [`use_effect`](dioxus::prelude::use_effect)).
///
/// Example:
/// ```rust

View file

@ -438,7 +438,7 @@ impl ScopeId {
/// Create a subscription that schedules a future render for the reference component. Unlike [`Self::needs_update`], this function will work outside of the dioxus runtime.
///
/// ## Notice: you should prefer using [`schedule_update_any`]
/// ## Notice: you should prefer using [`crate::prelude::schedule_update_any`]
pub fn schedule_update(&self) -> Arc<dyn Fn() + Send + Sync + 'static> {
Runtime::with_scope(*self, |cx| cx.schedule_update()).expect("to be in a dioxus runtime")
}

View file

@ -12,7 +12,7 @@
//! - `router`: exports the [router](https://dioxuslabs.com/learn/0.5/router) and enables any router features for the current platform
//! - `third-party-renderer`: Just disables warnings about no active platform when no renderers are enabled
//!
//! Platform features (the current platform determines what platform the [`launch`](dioxus::prelude::launch) function runs):
//! Platform features (the current platform determines what platform the [`launch()`] function runs):
//!
//! - `fullstack`: enables the fullstack platform. This must be used in combination with the `web` feature for wasm builds and `axum` feature for server builds
//! - `desktop`: enables the desktop platform

View file

@ -42,4 +42,4 @@
//! /// }
//! ///
//! /// We only track this when the template changes
//! pub discovered_templates: Vec<Template>,
//! pub discovered_templates: Vec<crate::Template>,