|
@@ -0,0 +1,291 @@
|
|
|
+
|
|
|
+# Reusing, Importing, and Exporting Components
|
|
|
+
|
|
|
+As your application grows in size, you'll want to start breaking your UI into components and, eventually, different files. This is a great idea to encapsulate functionality of your UI and scale your team.
|
|
|
+
|
|
|
+Let's say our app looks something like this:
|
|
|
+
|
|
|
+```shell
|
|
|
+├── Cargo.toml
|
|
|
+└── src
|
|
|
+ └── main.rs
|
|
|
+```
|
|
|
+
|
|
|
+```rust
|
|
|
+// main.rs
|
|
|
+use dioxus::prelude::*;
|
|
|
+
|
|
|
+fn main() {
|
|
|
+ dioxus::desktop::launch(App, |c| c);
|
|
|
+}
|
|
|
+
|
|
|
+fn App((cx, props): Component<()>) -> Element {}
|
|
|
+
|
|
|
+#[derive(PartialEq, Props)]
|
|
|
+struct PostProps{}
|
|
|
+fn Post((cx, props): Component<PostProps>) -> Element {}
|
|
|
+
|
|
|
+#[derive(PartialEq, Props)]
|
|
|
+struct VoteButtonsProps {}
|
|
|
+fn VoteButtons((cx, props): Component<VoteButtonsProps>) -> Element {}
|
|
|
+
|
|
|
+#[derive(PartialEq, Props)]
|
|
|
+struct TitleCardProps {}
|
|
|
+fn TitleCard((cx, props): Component<TitleCardProps>) -> Element {}
|
|
|
+
|
|
|
+#[derive(PartialEq, Props)]
|
|
|
+struct MetaCardProps {}
|
|
|
+fn MetaCard((cx, props): Component<MetaCardProps>) -> Element {}
|
|
|
+
|
|
|
+#[derive(PartialEq, Props)]
|
|
|
+struct ActionCardProps {}
|
|
|
+fn ActionCard((cx, props): Component<ActionCardProps>) -> Element {}
|
|
|
+```
|
|
|
+
|
|
|
+That's a lot of components for one file! We've successfully refactored our app into components, but we should probably start breaking it up into a file for each component.
|
|
|
+
|
|
|
+## Breaking into different files
|
|
|
+
|
|
|
+Fortunately, Rust has a built-in module system that's much cleaner than what you might be used to in JavaScript. Because `VoteButtons`, `TitleCard`, `MetaCard`, and `ActionCard` all belong to the `Post` component, let's put them all in a folder together called "post". We'll make a file for each component and move the props and render function.
|
|
|
+
|
|
|
+```rust
|
|
|
+// src/post/action.rs
|
|
|
+
|
|
|
+use dioxus::prelude::*;
|
|
|
+
|
|
|
+#[derive(PartialEq, Props)]
|
|
|
+struct ActionCardProps {}
|
|
|
+fn ActionCard((cx, props): Component<ActionCardProps>) -> Element {}
|
|
|
+```
|
|
|
+
|
|
|
+We should also create a `mod.rs` file in the `post` folder so we can use it from our `main.rs`. Our `Post` component and its props will go into this file.
|
|
|
+
|
|
|
+```shell
|
|
|
+├── Cargo.toml
|
|
|
+└── src
|
|
|
+ ├── main.rs
|
|
|
+ └── post
|
|
|
+ ├── vote.rs
|
|
|
+ ├── title.rs
|
|
|
+ ├── meta.rs
|
|
|
+ ├── action.rs
|
|
|
+ └── mod.rs
|
|
|
+```
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+In our `main.rs`, we'll want to declare the `post` module so we can access our `Post` component.
|
|
|
+
|
|
|
+```rust
|
|
|
+// main.rs
|
|
|
+use dioxus::prelude::*;
|
|
|
+
|
|
|
+fn main() {
|
|
|
+ dioxus::desktop::launch(App, |c| c);
|
|
|
+}
|
|
|
+
|
|
|
+mod post;
|
|
|
+
|
|
|
+fn App((cx, props): Component<()>) -> Element {
|
|
|
+ cx.render(rsx!{
|
|
|
+ post::Post {
|
|
|
+ id: Uuid::new_v4(),
|
|
|
+ score: 10,
|
|
|
+ comment_count: 10,
|
|
|
+ post_time: std::Instant::now(),
|
|
|
+ url: "example".to_string(),
|
|
|
+ title: "Title".to_string(),
|
|
|
+ original_poster: "me".to_string()
|
|
|
+ }
|
|
|
+ })
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+If you tried to build this app right now, you'll get an error message saying that `Post is private, trying changing it to public`. This is because we haven't properly exported our component! To fix this, we need to make sure both the Props and Component are declared as "public":
|
|
|
+
|
|
|
+```rust
|
|
|
+// src/post/mod.rs
|
|
|
+
|
|
|
+use dioxus::prelude::*;
|
|
|
+
|
|
|
+#[derive(PartialEq, Props)]
|
|
|
+pub struct PostProps {}
|
|
|
+pub fn Post((cx, props): Component<PostProps>) -> Element {}
|
|
|
+```
|
|
|
+
|
|
|
+While we're here, we also need to make sure each of our subcomponents are included as modules and exported.
|
|
|
+
|
|
|
+Our "post/mod.rs" file will eventually look like this:
|
|
|
+
|
|
|
+```rust
|
|
|
+use dioxus::prelude::*;
|
|
|
+
|
|
|
+mod vote;
|
|
|
+mod title;
|
|
|
+mod meta;
|
|
|
+mod action;
|
|
|
+
|
|
|
+#[derive(Properties, PartialEq)]
|
|
|
+pub struct PostProps {
|
|
|
+ id: uuid::Uuid,
|
|
|
+ score: i32,
|
|
|
+ comment_count: u32,
|
|
|
+ post_time: std::time::Instant,
|
|
|
+ url: String,
|
|
|
+ title: String,
|
|
|
+ original_poster: String
|
|
|
+}
|
|
|
+
|
|
|
+pub fn Post((cx, props): Component<PostProps>) -> Element {
|
|
|
+ cx.render(rsx!{
|
|
|
+ div { class: "post-container"
|
|
|
+ vote::VoteButtons {
|
|
|
+ score: props.score,
|
|
|
+ }
|
|
|
+ title::TitleCard {
|
|
|
+ title: props.title,
|
|
|
+ url: props.url,
|
|
|
+ }
|
|
|
+ meta::MetaCard {
|
|
|
+ original_poster: props.original_poster,
|
|
|
+ post_time: props.post_time,
|
|
|
+ }
|
|
|
+ action::ActionCard {
|
|
|
+ post_id: props.id
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+
|
|
|
+Ultimately, including and exporting components is governed by Rust's module system. [The Rust book is a great resource to learn about these concepts in greater detail.](https://doc.rust-lang.org/book/ch07-00-managing-growing-projects-with-packages-crates-and-modules.html)
|
|
|
+
|
|
|
+## Final structure:
|
|
|
+
|
|
|
+```shell
|
|
|
+├── Cargo.toml
|
|
|
+└── src
|
|
|
+ ├── main.rs
|
|
|
+ └── post
|
|
|
+ ├── vote.rs
|
|
|
+ ├── title.rs
|
|
|
+ ├── meta.rs
|
|
|
+ ├── action.rs
|
|
|
+ └── mod.rs
|
|
|
+```
|
|
|
+
|
|
|
+```rust
|
|
|
+// main.rs:
|
|
|
+use dioxus::prelude::*;
|
|
|
+
|
|
|
+fn main() {
|
|
|
+ dioxus::desktop::launch(App, |c| c);
|
|
|
+}
|
|
|
+
|
|
|
+mod post;
|
|
|
+
|
|
|
+fn App((cx, props): Component<()>) -> Element {
|
|
|
+ cx.render(rsx!{
|
|
|
+ post::Post {
|
|
|
+ id: Uuid::new_v4(),
|
|
|
+ score: 10,
|
|
|
+ comment_count: 10,
|
|
|
+ post_time: std::Instant::now(),
|
|
|
+ url: "example".to_string(),
|
|
|
+ title: "Title".to_string(),
|
|
|
+ original_poster: "me".to_string()
|
|
|
+ }
|
|
|
+ })
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+
|
|
|
+```rust
|
|
|
+// src/post/mod.rs
|
|
|
+use dioxus::prelude::*;
|
|
|
+
|
|
|
+mod vote;
|
|
|
+mod title;
|
|
|
+mod meta;
|
|
|
+mod action;
|
|
|
+
|
|
|
+#[derive(Properties, PartialEq)]
|
|
|
+pub struct PostProps {
|
|
|
+ id: uuid::Uuid,
|
|
|
+ score: i32,
|
|
|
+ comment_count: u32,
|
|
|
+ post_time: std::time::Instant,
|
|
|
+ url: String,
|
|
|
+ title: String,
|
|
|
+ original_poster: String
|
|
|
+}
|
|
|
+
|
|
|
+pub fn Post((cx, props): Component<PostProps>) -> Element {
|
|
|
+ cx.render(rsx!{
|
|
|
+ div { class: "post-container"
|
|
|
+ vote::VoteButtons {
|
|
|
+ score: props.score,
|
|
|
+ }
|
|
|
+ title::TitleCard {
|
|
|
+ title: props.title,
|
|
|
+ url: props.url,
|
|
|
+ }
|
|
|
+ meta::MetaCard {
|
|
|
+ original_poster: props.original_poster,
|
|
|
+ post_time: props.post_time,
|
|
|
+ }
|
|
|
+ action::ActionCard {
|
|
|
+ post_id: props.id
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+```rust
|
|
|
+// src/post/vote.rs
|
|
|
+use dioxus::prelude::*;
|
|
|
+
|
|
|
+#[derive(PartialEq, Props)]
|
|
|
+pub struct VoteButtonsProps {}
|
|
|
+pub fn VoteButtons((cx, props): Component<VoteButtonsProps>) -> Element {}
|
|
|
+```
|
|
|
+
|
|
|
+```rust
|
|
|
+// src/post/title.rs
|
|
|
+use dioxus::prelude::*;
|
|
|
+
|
|
|
+#[derive(PartialEq, Props)]
|
|
|
+pub struct TitleCardProps {}
|
|
|
+pub fn TitleCard((cx, props): Component<TitleCardProps>) -> Element {}
|
|
|
+```
|
|
|
+
|
|
|
+```rust
|
|
|
+// src/post/meta.rs
|
|
|
+use dioxus::prelude::*;
|
|
|
+
|
|
|
+#[derive(PartialEq, Props)]
|
|
|
+pub struct MetaCardProps {}
|
|
|
+pub fn MetaCard((cx, props): Component<MetaCardProps>) -> Element {}
|
|
|
+```
|
|
|
+
|
|
|
+```rust
|
|
|
+// src/post/action.rs
|
|
|
+use dioxus::prelude::*;
|
|
|
+
|
|
|
+#[derive(PartialEq, Props)]
|
|
|
+pub struct ActionCardProps {}
|
|
|
+pub fn ActionCard((cx, props): Component<ActionCardProps>) -> Element {}
|
|
|
+```
|
|
|
+
|
|
|
+## Moving forward
|
|
|
+
|
|
|
+Next chapter, we'll start to add use code to hide and show Elements with conditional rendering.
|
|
|
+
|
|
|
+For more reading on components:
|
|
|
+
|
|
|
+- [Components in depth]()
|
|
|
+- [Lifecycles]()
|
|
|
+- [The Context object]()
|
|
|
+- [Optional Prop fields]()
|