Add a better introduction to what Components are.
This commit is contained in:
1 parent
fc7d94b8d1
commit
f5907a682e
4 files changed
+50
-33
No files matched your search
Binary file not shown.
|
After Width: | Height: | Size: 8.2 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 4.1 KiB |
@@ -12,32 +12,10 @@ In short, a component is a special function that takes input properties and outp
|
|||||||
|
|
||||||
### Real-world example
|
### Real-world example
|
||||||
|
|
||||||
Take a look at a post on Reddit:
|
Let's use a Reddit post as an example:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
We can build this post as a component, consisting of multiple subcomponents. It has several inputs:
|
|
||||||
|
|
||||||
- The score
|
|
||||||
- The number of comments
|
|
||||||
- How long ago it was posted
|
|
||||||
- The url short address
|
|
||||||
- The title
|
|
||||||
- The username of the original poster
|
|
||||||
|
|
||||||
If we wanted to sketch out these requirements in Rust, we would start with a struct:
|
|
||||||
|
|
||||||
```rust
|
|
||||||
struct PostData {
|
|
||||||
score: i32,
|
|
||||||
comment_count: u32,
|
|
||||||
post_time: Instant,
|
|
||||||
url: String,
|
|
||||||
title: String,
|
|
||||||
original_poster_name: String
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
If we look at the layout of the component, we notice quite a few buttons and pieces of functionality:
|
If we look at the layout of the component, we notice quite a few buttons and pieces of functionality:
|
||||||
|
|
||||||
- Upvote/Downvote
|
- Upvote/Downvote
|
||||||
@@ -52,7 +30,7 @@ If we look at the layout of the component, we notice quite a few buttons and pie
|
|||||||
- View article
|
- View article
|
||||||
- Visit user
|
- Visit user
|
||||||
|
|
||||||
If we included all this functionality in one `rsx!` call it would be huge! Instead, let's break the post down into some core pieces:
|
If we included all this functionality in one `rsx!` call it would be huge! Instead, let's break the post down into Components:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
@@ -61,4 +39,4 @@ If we included all this functionality in one `rsx!` call it would be huge! Inste
|
|||||||
- **MetaCard**: Original Poster, Time Submitted
|
- **MetaCard**: Original Poster, Time Submitted
|
||||||
- **ActionCard**: View comments, Share, Save, Hide, Give award, Report, Crosspost
|
- **ActionCard**: View comments, Share, Save, Hide, Give award, Report, Crosspost
|
||||||
|
|
||||||
In this chapter, we'll learn how to define our own components.
|
In this chapter, we'll learn how to define these components.
|
||||||
@@ -7,7 +7,7 @@ Dioxus components are functions that accept Props as input and output an Element
|
|||||||
- The inline_props macro
|
- The inline_props macro
|
||||||
|
|
||||||
## Props
|
## Props
|
||||||
All properties that your components take must implement the `Props` trait. We can derive this trait on our own structs to define a Component's props.
|
The input of your Component must be passed in a single struct, which must implement the `Props` trait. We can derive this trait automatically with `#[derive(Props)]`.
|
||||||
|
|
||||||
> Dioxus `Props` is very similar to [@idanarye](https://github.com/idanarye)'s [TypedBuilder crate](https://github.com/idanarye/rust-typed-builder) and supports many of the same parameters.
|
> Dioxus `Props` is very similar to [@idanarye](https://github.com/idanarye)'s [TypedBuilder crate](https://github.com/idanarye/rust-typed-builder) and supports many of the same parameters.
|
||||||
|
|
||||||
@@ -20,16 +20,41 @@ There are 2 flavors of Props: owned and borrowed.
|
|||||||
|
|
||||||
Owned Props are very simple – they don't borrow anything. Example:
|
Owned Props are very simple – they don't borrow anything. Example:
|
||||||
```rust
|
```rust
|
||||||
#[derive(Props, PartialEq)]
|
// Remember: owned props must implement PartialEq!
|
||||||
struct MyProps {
|
#[derive(PartialEq, Props)]
|
||||||
name: String
|
struct VoteButtonProps {
|
||||||
|
score: i32
|
||||||
}
|
}
|
||||||
|
|
||||||
fn Demo(cx: Scope<MyProps>) -> Element {
|
fn VoteButton(cx: Scope<VoteButtonProps>) -> Element {
|
||||||
todo!()
|
cx.render(rsx!{
|
||||||
|
div {
|
||||||
|
div { "+" }
|
||||||
|
div { "{cx.props.score}"}
|
||||||
|
div { "-" }
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Now, we can use the VoteButton Component like we would use a regular HTML element:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn main() {
|
||||||
|
dioxus::desktop::launch(App);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn App(cx: Scope) -> Element {
|
||||||
|
cx.render(rsx! (
|
||||||
|
VoteButton { score: 42 }
|
||||||
|
))
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
And we can see that the Component indeed gets rendered:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
> The simplest Owned Props you can have is `()` - or no value at all. This is what the `App` Component takes as props. `Scope` accepts a generic for the Props which defaults to `()`.
|
> The simplest Owned Props you can have is `()` - or no value at all. This is what the `App` Component takes as props. `Scope` accepts a generic for the Props which defaults to `()`.
|
||||||
>
|
>
|
||||||
> ```rust
|
> ```rust
|
||||||
@@ -42,7 +67,7 @@ fn Demo(cx: Scope<MyProps>) -> Element {
|
|||||||
|
|
||||||
### Borrowed Props
|
### Borrowed Props
|
||||||
|
|
||||||
Owning a string works well as long as you only need it in one place. But what if we need to pass a String from a `Post` Component to a `TitleCard` subcomponent? A naive solution might be to [`.clone()`](https://doc.rust-lang.org/std/clone/trait.Clone.html) the String, creating a copy of it – but this would be inefficient, especially for larger Strings.
|
Owning props works well if your props are easy to copy around - like a single number. But what if we need to pass a larger data type, like a String from an `App` Component to a `TitleCard` subcomponent? A naive solution might be to [`.clone()`](https://doc.rust-lang.org/std/clone/trait.Clone.html) the String, creating a copy of it for the subcomponent – but this would be inefficient, especially for larger Strings.
|
||||||
|
|
||||||
Rust allows for something more efficient – borrowing the String as a `&str`. Instead of creating a copy, this will give us a reference to the original String – this is what Borrowed Props are for!
|
Rust allows for something more efficient – borrowing the String as a `&str`. Instead of creating a copy, this will give us a reference to the original String – this is what Borrowed Props are for!
|
||||||
|
|
||||||
@@ -61,7 +86,21 @@ fn TitleCard<'a>(cx: Scope<'a, TitleCardProps<'a>>) -> Element {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
This lifetime `'a` tells the compiler that as long as `title` exists, the String it was created from must also exist. Dioxus will happily accept such a component.
|
This lifetime `'a` tells the compiler that as long as `title` exists, the String it was created from must also exist. Dioxus will happily accept such a component – we can now render it alongside our VoteButton!
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn App(cx: Scope) -> Element {
|
||||||
|
// For the sake of an example, we create the &str here.
|
||||||
|
// But you might as well borrow it from an owned String type.
|
||||||
|
let hello = "Hello Dioxus!";
|
||||||
|
|
||||||
|
cx.render(rsx! (
|
||||||
|
VoteButton { score: 42 },
|
||||||
|
TitleCard { title: hello }
|
||||||
|
))
|
||||||
|
}
|
||||||
|
```
|
||||||
|

|
||||||
|
|
||||||
## Memoization
|
## Memoization
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user