1
0
Jonathan Kelley 3 жил өмнө
parent
commit
1560e2daca

+ 1 - 0
docs/guide/.vscode/spellright.dict

@@ -1,2 +1,3 @@
 oninput
 Webview
+idanarye

+ 4 - 3
docs/guide/src/SUMMARY.md

@@ -9,9 +9,10 @@
   - [Lists](elements/lists.md)
   - [Special Attributes](elements/special_attributes.md)
 - [Components](elements/components.md)
-  - [Component Properties](elements/propsmacro.md)
-  - [Reusing, Importing, and Exporting Components](elements/exporting_components.md)
-  - [Component Children and Attributes](elements/component_children.md)
+  - [Properties](elements/propsmacro.md)
+  - [Reusing, Importing, and Exporting](elements/exporting_components.md)
+  - [Children and Attributes](elements/component_children.md)
+  - [Composing Components](elements/composing.md)
 - [Adding Interactivity](interactivity/index.md)
   - [Hooks and Internal State](interactivity/hooks.md)
   - [Event handlers](interactivity/event_handlers.md)

+ 3 - 0
docs/guide/src/async/fetching.md

@@ -1 +1,4 @@
 # Fetching
+
+
+This section is currently under construction! 🏗

+ 3 - 0
docs/guide/src/async/index.md

@@ -17,3 +17,6 @@ Writing apps that deal with Send/Sync can be frustrating at times. Under the hoo
 
 
 All async code in your app is polled on a `LocalSet`, so any async code we w
+
+
+> This section is currently under construction! 🏗

+ 43 - 0
docs/guide/src/elements/composing.md

@@ -0,0 +1,43 @@
+# Composing Components
+
+So far, we've talked about declaring new components and setting up their properties. However, we haven't really talked about how components work together and how your app is updated.
+
+In this section, we'll talk about:
+
+- Sharing data between components
+- How the UI is updated from input and state changes
+- Forcing renders
+- How renders propagate
+- 
+
+
+### Rendering our posts with a PostList component
+
+Let's start by modeling this problem with a component and some properties. 
+
+For this example, we're going to use the borrowed component syntax since we probably have a large list of posts that we don't want to clone every time we render the Post List.
+
+```rust
+#[derive(Props, PartialEq)]
+struct PostListProps<'a> {
+    posts: &'a [PostData]
+}
+```
+Next, we're going to define our component:
+
+```rust
+fn App(cx: Scope<PostList>) -> Element {
+    cx.render(rsx!{
+        ul { class: "post-list",
+            // we can drop an iterator directly into our elements
+            cx.props.posts.iter().map(|post| rsx!{
+                Post {
+                    title: post.title,
+                    age: post.age,
+                    original_poster: post.original_poster
+                }
+            })
+        }
+    })
+}
+```

+ 12 - 33
docs/guide/src/elements/lists.md

@@ -45,10 +45,21 @@ Finally, we can include this list in the final structure:
 ```rust
 rsx!(
     ul {
-        {name_list}
+        name_list
     }
 )
 ```
+Or, we can include the iterator inline:
+```rust
+rsx!(
+    ul {
+        names.iter().map(|name| rsx!(
+            li { "{name}" } 
+        ))
+    }
+)
+```
+
 The HTML-rendered version of this list would follow what you would expect:
 ```html
 <ul>
@@ -59,38 +70,6 @@ The HTML-rendered version of this list would follow what you would expect:
 </ul>
 ```
 
-### Rendering our posts with a PostList component
-
-Let's start by modeling this problem with a component and some properties. 
-
-For this example, we're going to use the borrowed component syntax since we probably have a large list of posts that we don't want to clone every time we render the Post List.
-
-```rust
-#[derive(Props, PartialEq)]
-struct PostListProps<'a> {
-    posts: &'a [PostData]
-}
-```
-Next, we're going to define our component:
-
-```rust
-fn App(cx: Scope<PostList>) -> Element {
-    cx.render(rsx!{
-        ul { class: "post-list",
-            // we can drop an iterator directly into our elements
-            cx.props.posts.iter().map(|post| rsx!{
-                Post {
-                    title: post.title,
-                    age: post.age,
-                    original_poster: post.original_poster
-                }
-            })
-        }
-    })
-}
-```
-
-
 ## Filtering Iterators
 
 Rust's iterators are extremely powerful, especially when used for filtering tasks. When building user interfaces, you might want to display a list of items filtered by some arbitrary check.

+ 145 - 0
docs/guide/src/elements/propsmacro.md

@@ -9,6 +9,151 @@ All component `properties` must implement the `Properties` trait. The `Props` ma
 
 
 
+## Using the Props Macro
+
+All `properties` that your components take must implement the `Properties` trait. The simplest props you can use is simply `()` - or no value at all. `Scope` is generic over your component's props and actually defaults to `()`.
+
+```rust
+// this scope
+Scope<()> 
+
+// is the same as this scope
+Scope
+```
+
+If we wanted to define a component with its own props, we would create a new struct and tack on the `Props` derive macro:
+
+```rust
+#[derive(Props)]
+struct MyProps {
+    name: String
+}
+```
+This particular code will not compile - all `Props` must either a) borrow from their parent or b) implement `PartialEq`. Since our props do not borrow from their parent, they are `'static` and must implement PartialEq.
+
+For an owned example:
+```rust
+#[derive(Props, PartialEq)]
+struct MyProps {
+    name: String
+}
+```
+
+For a borrowed example:
+```rust
+#[derive(Props)]
+struct MyProps<'a> {
+    name: &'a str
+}
+```
+
+Then, to use these props in our component, we simply swap out the generic parameter on scope.
+
+For owned props, we just drop it in:
+
+```rust
+fn Demo(cx: Scope<MyProps>) -> Element {
+    todo!()
+}
+```
+
+However, for props that borrow data, we need to explicitly declare lifetimes. Rust does not know that our props and our component share the same lifetime, so must explicitly attach a lifetime in two places:
+
+```rust
+fn Demo<'a>(cx: Scope<'a, MyProps<'a>>) -> Element {
+    todo!()
+}
+```
+
+By putting the `'a` lifetime on Scope and our Props, we can now borrow data from our parent and pass it on to our children.
+
+
+## Memoization
+
+If you're coming from React, you might be wondering how memoization fits in. For our purpose, memoization is the process in which we check if a component actually needs to be re-rendered when its props change. If a component's properties change but they wouldn't necessarily affect the output, then we don't need to actually re-render the component.
+
+For example, let's say we have a component that has two children:
+
+```rust
+fn Demo(cx: Scope) -> Element {
+    let name = use_state(&cx, || String::from("bob"));
+    let age = use_state(&cx, || 21);
+
+    cx.render(rsx!{
+        Name { name: name }
+        Age { age: age }
+    })
+}
+```
+
+If `name` changes but `age` does not, then there is no reason to re-render our `Age` component since the contents of its props did not meaningfully change.
+
+
+Dioxus implements memoization by default, which means you can always rely on props with `PartialEq` or no props at all to act as barriers in your app. This can be extremely useful when building larger apps where properties frequently change. By moving our state into a global state management solution, we can achieve precise, surgical re-renders, improving the performance of our app.
+
+
+However, for components that borrow values from their parents, we cannot safely memoize them.
+
+For example, this component borrows `&str` - and if the parent re-renders, then the actual reference to `str` will probably be different. Since the data is borrowed, we need to pass a new version down the tree.
+
+```rust
+#[derive(Props)]
+struct MyProps<'a> {
+    name: &'a str
+}
+
+fn Demo<'a>(cx: Scope<'a, MyProps<'a>>) -> Element {
+    todo!()
+}
+```
+
+TLDR: 
+- if you see props with a lifetime or generics, it cannot be memoized
+- memoization is done automatically through the `PartialEq` trait
+- components with empty props can act as memoization barriers
+
+## Optional Fields
+
+Dioxus' `Props` macro 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.
+
+For example, you can easily create optional fields by attaching the `optional` modifier to a field.
+
+```rust
+#[derive(Props, PartialEq)]
+struct MyProps {
+    name: String,
+
+    #[props(optional)]
+    description: Option<String>
+}
+
+fn Demo(cx: MyProps) -> Element {
+    ...
+}
+```
+
+Then, we can completely omit the description field when calling the component:
+
+```rust
+rsx!{
+    Demo {
+        name: "Thing".to_string(),
+        // description is omitted
+    }
+}
+```
+
+The `optional` modifier is a combination of two separate modifiers: `default` and `strip_option`. The full list of modifiers includes:
+
+- `default` - automatically add the field using its `Default` implementation
+- `strip_option` - automatically wrap values at the call site in `Some`
+- `optional` - combine both `default` and `strip_option`
+- `into` - automatically call `into` on the value at the callsite
+
+For more information on how tags work, check out the [TypedBuilder](https://github.com/idanarye/rust-typed-builder) crate. However, all attributes for props in Dioxus are flattened (no need for `setter` syntax) and the `optional` field is new.
+
+
+
 
 ## The inline_props macro
 

+ 17 - 8
docs/guide/src/elements/special_attributes.md

@@ -30,9 +30,7 @@ fn BlogPost(cx: Scope) -> Element {
 }
 ```
 
-> Note! 
-
-This attribute is called "dangerous_inner_html" because it is DANGEROUS. If you're not careful, you can easily expose cross-site-scripting (XSS) attacks to your users. If you're handling untrusted input, make sure to escape your HTML before passing it into `dangerous_inner_html`.
+> Note! This attribute is called "dangerous_inner_html" because it is DANGEROUS. If you're not careful, you can easily expose cross-site-scripting (XSS) attacks to your users. If you're handling untrusted input, make sure to escape your HTML before passing it into `dangerous_inner_html`.
 
 
 ## Boolean Attributes
@@ -87,13 +85,13 @@ Not all attributes work like this however. Only *these specific attributes* are
 
 For any other attributes, a value of `"false"` will be sent directly to the DOM.
 
-## `prevent_default`
+## Stopping form input and navigation with `prevent_default`
 
-Currently, preventing default on events from an event handler is not possible from Desktop/Mobile. Until this is supported, it's possible to prevent default using the `prevent_default` attribute. 
+Currently, calling `prevent_default` on events in EventHandlers is not possible from Desktop/Mobile. Until this is supported, it's possible to prevent default using the `prevent_default` attribute. 
 
 > Note: you cannot conditionally prevent default with this approach. This is a limitation until synchronous event handling is available across the Webview boundary 
 
-To use `prevent_default`, simple use the `prevent_default` attribute and set it to the name of the event handler you want to prevent default on. We can attach this attribute multiple times for multiple attributes.
+To use `prevent_default`, simply attach the `prevent_default` attribute to a given element and set it to the name of the event handler you want to prevent default on. We can attach this attribute multiple times for multiple attributes.
 
 ```rust
 rsx!{
@@ -107,7 +105,7 @@ rsx!{
 }
 ```
 
-## `..Attributes`
+## Passing attributes into children: `..Attributes`
 
 Just like Dioxus supports spreading component props into components, we also support spreading attributes into elements. This lets you pass any arbitrary attributes through components into elements.
 
@@ -131,7 +129,6 @@ pub fn StateInput<'a>(cx: Scope<'a, InputProps<'a>>) -> Element {
 
 ## Controlled inputs and `value`, `checked`, and `selected`
 
-
 In Dioxus, there is a distinction between controlled and uncontrolled inputs. Most inputs you'll use are "controlled," meaning we both drive the `value` of the input and react to the `oninput`.
 
 Controlled components:
@@ -179,3 +176,15 @@ rsx!{
 ```
 
 ## Wrapping up
+
+We've reached just about the end of what you can do with elements without venturing into "advanced" territory.
+
+In this chapter, we learned:
+- How to declare elements
+- How to conditionally render parts of your UI
+- How to render lists
+- Which attributes are "special"
+
+There's more to elements! For further reading, check out:
+
+- [Custom Elements]()

+ 2 - 0
docs/guide/src/interactivity/event_handlers.md

@@ -1 +1,3 @@
 # Event handlers
+
+> This section is currently under construction! 🏗

+ 2 - 0
docs/guide/src/interactivity/lifecycles.md

@@ -1 +1,3 @@
 # Lifecycle, updates, and effects
+
+> This section is currently under construction! 🏗

+ 3 - 0
docs/guide/src/interactivity/user_input.md

@@ -1,3 +1,6 @@
 # User Input and Controlled Components
 
 Handling user input is one of the most common things your app will do, but it can be tricky
+
+
+> This section is currently under construction! 🏗

+ 1 - 0
docs/guide/src/state/errorhandling.md

@@ -9,3 +9,4 @@ fn App((cx, props): Component) -> Element {
 }
 ```
 
+> This section is currently under construction! 🏗

+ 1 - 0
docs/guide/src/state/index.md

@@ -7,6 +7,7 @@ In this chapter, we'll cover the various ways to manage state, the appropriate t
 ## Terminology 
 
 
+> This section is currently under construction! 🏗
 
 
 

+ 3 - 0
docs/guide/src/state/liftingstate.md

@@ -1 +1,4 @@
 # Lifting State
+
+
+> This section is currently under construction! 🏗

+ 3 - 0
docs/guide/src/state/localstate.md

@@ -1 +1,4 @@
 # Local State
+
+
+> This section is currently under construction! 🏗

+ 6 - 0
docs/guide/src/state/sharedstate.md

@@ -1 +1,7 @@
 # Global State
+
+
+cx.provide_context()
+cx.consume_context()
+
+> This section is currently under construction! 🏗

+ 2 - 0
docs/guide/src/tutorial/components.md

@@ -1 +1,3 @@
 # Defining Components
+
+This section is currently under construction! 🏗

+ 2 - 0
docs/guide/src/tutorial/state.md

@@ -1 +1,3 @@
 # Defining State
+
+This section is currently under construction! 🏗

+ 3 - 0
docs/guide/src/tutorial/structure.md

@@ -1 +1,4 @@
 # Structuring our app
+
+
+This section is currently under construction! 🏗

+ 3 - 0
docs/guide/src/tutorial/styling.md

@@ -1 +1,4 @@
 # Styling
+
+
+This section is currently under construction! 🏗