|
@@ -34,11 +34,11 @@ Remember: Dioxus is a library for declaring interactive user interfaces—it is
|
|
|
|
|
|
## Brief Overview
|
|
|
|
|
|
-All Dioxus apps are built by composing functions that return an `Element`.
|
|
|
+All Dioxus apps are built by composing functions that return an `Element`.
|
|
|
|
|
|
To launch an app, we use the `launch` method and use features in ``Cargo.toml`` to specify which renderer we want to use. In the launch function, we pass the app's root `Component`.
|
|
|
|
|
|
-```rust, ignore
|
|
|
+```rust
|
|
|
use dioxus::prelude::*;
|
|
|
|
|
|
fn main() {
|
|
@@ -49,7 +49,7 @@ fn main() {
|
|
|
// It's not required, but highly recommended. For example, UpperCamelCase components will not generate a warning.
|
|
|
#[component]
|
|
|
fn App() -> Element {
|
|
|
- rsx!("hello world!")
|
|
|
+ rsx! { "hello world!" }
|
|
|
}
|
|
|
```
|
|
|
|
|
@@ -67,25 +67,25 @@ children.
|
|
|
```rust, ignore
|
|
|
let value = "123";
|
|
|
|
|
|
-rsx!(
|
|
|
+rsx! {
|
|
|
div {
|
|
|
class: "my-class {value}", // <--- attribute
|
|
|
onclick: move |_| info!("clicked!"), // <--- listener
|
|
|
h1 { "hello world" }, // <--- child
|
|
|
}
|
|
|
-)
|
|
|
+}
|
|
|
```
|
|
|
|
|
|
-The `rsx!` macro accepts attributes in "struct form" and will parse the rest
|
|
|
-of the body as child elements and rust expressions. Any rust expression that
|
|
|
-implements `IntoIterator<Item = impl IntoVNode>` will be parsed as a child.
|
|
|
+The `rsx!` macro accepts attributes in "struct form". Any rust expression contained within curly braces that implements `IntoIterator<Item = impl IntoVNode>` will be parsed as a child. We make two exceptions: both `for` loops and `if` statements are parsed where their body is parsed as a child.
|
|
|
|
|
|
```rust, ignore
|
|
|
-rsx!(
|
|
|
+rsx! {
|
|
|
div {
|
|
|
- (0..10).map(|_| rsx!(span { "hello world" }))
|
|
|
+ for _ in 0..10 {
|
|
|
+ span { "hello world" }
|
|
|
+ }
|
|
|
}
|
|
|
-)
|
|
|
+}
|
|
|
```
|
|
|
|
|
|
The `rsx!` macro is what generates the `Element` that our components return.
|
|
@@ -93,7 +93,7 @@ The `rsx!` macro is what generates the `Element` that our components return.
|
|
|
```rust, ignore
|
|
|
#[component]
|
|
|
fn Example() -> Element {
|
|
|
- rsx!("hello world")
|
|
|
+ rsx!{ "hello world" }
|
|
|
}
|
|
|
```
|
|
|
|
|
@@ -104,20 +104,14 @@ elements:
|
|
|
#[component]
|
|
|
fn App() -> Element {
|
|
|
let name = "dave";
|
|
|
- rsx!(
|
|
|
+ rsx! {
|
|
|
h1 { "Hello, {name}!" }
|
|
|
- div {
|
|
|
- class: "my-class",
|
|
|
- id: "my-id",
|
|
|
-
|
|
|
- (0..5).map(|i| rsx!(
|
|
|
- div { key: "{i}"
|
|
|
- "FizzBuzz: {i}"
|
|
|
- }
|
|
|
- ))
|
|
|
-
|
|
|
+ div { class: "my-class", id: "my-id",
|
|
|
+ for i in 0..5 {
|
|
|
+ div { "FizzBuzz: {i}" }
|
|
|
+ }
|
|
|
}
|
|
|
- )
|
|
|
+ }
|
|
|
}
|
|
|
```
|
|
|
|
|
@@ -125,19 +119,19 @@ fn App() -> Element {
|
|
|
|
|
|
We can compose these function components to build a complex app. Each new
|
|
|
component we design must take some Properties. For components with no explicit
|
|
|
-properties, we can use the `()` type or simply omit the type altogether.
|
|
|
+properties we can omit the type altogether.
|
|
|
|
|
|
-In Dioxus, all properties are memoized by default!
|
|
|
+In Dioxus, all properties are memoized by default, and this implement both Clone and PartialEq. For props you can't clone, simply wrap the fields in a ReadOnlySignal and Dioxus will handle the wrapping for you.
|
|
|
|
|
|
```rust, ignore
|
|
|
#[component]
|
|
|
fn App() -> Element {
|
|
|
- rsx!(
|
|
|
+ rsx! {
|
|
|
Header {
|
|
|
title: "My App",
|
|
|
color: "red",
|
|
|
}
|
|
|
- )
|
|
|
+ }
|
|
|
}
|
|
|
```
|
|
|
|
|
@@ -154,12 +148,12 @@ struct HeaderProps {
|
|
|
|
|
|
#[component]
|
|
|
fn Header(props: HeaderProps) -> Element {
|
|
|
- rsx!(
|
|
|
+ rsx! {
|
|
|
div {
|
|
|
background_color: "{props.color}"
|
|
|
h1 { "{props.title}" }
|
|
|
}
|
|
|
- )
|
|
|
+ }
|
|
|
}
|
|
|
```
|
|
|
|
|
@@ -169,35 +163,12 @@ struct from function arguments:
|
|
|
```rust, ignore
|
|
|
#[component]
|
|
|
fn Header(title: String, color: String) -> Element {
|
|
|
- rsx!(
|
|
|
+ rsx! {
|
|
|
div {
|
|
|
background_color: "{color}"
|
|
|
h1 { "{title}" }
|
|
|
}
|
|
|
- )
|
|
|
-}
|
|
|
-```
|
|
|
-
|
|
|
-Components may also borrow data from their parent component. We just need to
|
|
|
-attach some lifetimes to the props struct.
|
|
|
-
|
|
|
-> Note: we don't need to derive `PartialEq` for borrowed props since they cannot be memoized.
|
|
|
-
|
|
|
-```rust, ignore
|
|
|
-#[derive(Props)]
|
|
|
-struct HeaderProps<'a> {
|
|
|
- title: &'a str,
|
|
|
- color: &'a str,
|
|
|
-}
|
|
|
-
|
|
|
-#[component]
|
|
|
-fn Header<'a>(props: HeaderProps<'a>) -> Element {
|
|
|
- rsx!(
|
|
|
- div {
|
|
|
- background_color: "{props.color}"
|
|
|
- h1 { "{props.title}" }
|
|
|
- }
|
|
|
- )
|
|
|
+ }
|
|
|
}
|
|
|
```
|
|
|
|
|
@@ -205,23 +176,11 @@ Components that begin with an uppercase letter may be called with
|
|
|
the traditional (for React) curly-brace syntax like so:
|
|
|
|
|
|
```rust, ignore
|
|
|
-rsx!(
|
|
|
+rsx! {
|
|
|
Header { title: "My App" }
|
|
|
-)
|
|
|
-```
|
|
|
-
|
|
|
-Alternatively, if your components begin with a lowercase letter, you can use
|
|
|
-the function call syntax:
|
|
|
-
|
|
|
-```rust, ignore
|
|
|
-rsx!(
|
|
|
- header( title: "My App" )
|
|
|
-)
|
|
|
+}
|
|
|
```
|
|
|
|
|
|
-However, the convention is to use UpperCamelCase. The `#[component]` attribute will enforce this,
|
|
|
-but you can turn it off if you wish.
|
|
|
-
|
|
|
## Hooks
|
|
|
|
|
|
While components are reusable forms of UI elements, hooks are reusable forms
|
|
@@ -236,7 +195,7 @@ use hooks to define the state and modify it from within listeners.
|
|
|
fn App() -> Element {
|
|
|
let name = use_signal(|| "world");
|
|
|
|
|
|
- rsx!("hello {name}!")
|
|
|
+ rsx! { "hello {name}!" }
|
|
|
}
|
|
|
```
|
|
|
|
|
@@ -263,7 +222,7 @@ fn use_username(d: Uuid) -> bool {
|
|
|
To create entirely new foundational hooks, we can use the `use_hook` method.
|
|
|
|
|
|
```rust, ignore
|
|
|
-fn use_mut_string() -> &mut String {
|
|
|
+fn use_mut_string() -> String {
|
|
|
use_hook(|_| "Hello".to_string())
|
|
|
}
|
|
|
```
|
|
@@ -283,12 +242,12 @@ fn main() {
|
|
|
|
|
|
#[component]
|
|
|
fn App() -> Element {
|
|
|
- let count = use_signal(|| 0);
|
|
|
+ let mut count = use_signal(|| 0);
|
|
|
|
|
|
rsx!(
|
|
|
div { "Count: {count}" }
|
|
|
- button { onclick: move |_| count.set(count + 1), "Increment" }
|
|
|
- button { onclick: move |_| count.set(count - 1), "Decrement" }
|
|
|
+ button { onclick: move |_| count += 1, "Increment" }
|
|
|
+ button { onclick: move |_| count -= 1, "Decrement" }
|
|
|
)
|
|
|
}
|
|
|
```
|
|
@@ -311,21 +270,4 @@ Beyond this overview, Dioxus supports:
|
|
|
- Basic fine-grained reactivity (IE SolidJS/Svelte)
|
|
|
- and more!
|
|
|
|
|
|
-Good luck!
|
|
|
-
|
|
|
-## Inspiration, Resources, Alternatives, and Credits
|
|
|
-
|
|
|
-Dioxus is inspired by:
|
|
|
-
|
|
|
-- React: for its hooks, concurrency, suspense
|
|
|
-- Dodrio: for its research in bump allocation, double buffering, and diffing architecture
|
|
|
-
|
|
|
-Alternatives to Dioxus include:
|
|
|
-
|
|
|
-- Yew: supports function components and web, but no SSR, borrowed data, or bump allocation. Rather slow at times.
|
|
|
-- Percy: supports function components, web, ssr, but lacks state management
|
|
|
-- Sycamore: supports function components, web, ssr, but is closer to SolidJS than React
|
|
|
-- MoonZoom/Seed: opinionated frameworks based on the Elm model (message, update)—no hooks
|
|
|
-
|
|
|
-We've put a lot of work into making Dioxus ergonomic and _familiar_.
|
|
|
-Our target audience is TypeScript developers looking to switch to Rust for the web—so we need to be comparable to React.
|
|
|
+Build cool things ✌️
|