From 9874f342e2bc1116410142c691545d75b0e0d6fe Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Mon, 1 Nov 2021 18:38:09 -0400 Subject: [PATCH] docs: more docs --- docs/guide/src/SUMMARY.md | 3 +- docs/guide/src/concepts/components.md | 8 +- .../src/concepts/conditional_rendering.md | 10 +- docs/guide/src/concepts/event_handlers.md | 10 + docs/guide/src/concepts/interactivity.md | 184 ++++++++++++++++++ docs/guide/src/concepts/usestate.md | 1 + docs/guide/src/concepts/vnodes.md | 2 +- docs/guide/src/images/component_tree.png | Bin 0 -> 3724 bytes docs/guide/src/images/diffing.png | Bin 0 -> 23486 bytes packages/core/src/context.rs | 10 +- 10 files changed, 212 insertions(+), 16 deletions(-) create mode 100644 docs/guide/src/concepts/usestate.md create mode 100644 docs/guide/src/images/component_tree.png create mode 100644 docs/guide/src/images/diffing.png diff --git a/docs/guide/src/SUMMARY.md b/docs/guide/src/SUMMARY.md index cb710c33d..14e12b45b 100644 --- a/docs/guide/src/SUMMARY.md +++ b/docs/guide/src/SUMMARY.md @@ -11,6 +11,8 @@ - [Lists](concepts/lists.md) - [Adding Interactivity](concepts/interactivity.md) - [Event handlers](concepts/event_handlers.md) + - [Hooks and Internal State](concepts/hooks.md) + - [Fundamental Hooks and `use_hook`](concepts/usestate.md) - [User Input and Controlled Components](concepts/errorhandling.md) - [Lifecycle, updates, and effects](concepts/lifecycles.md) @@ -30,7 +32,6 @@ Extracting State Logic into a Reducer Passing Data Deeply with Context Scaling Up with Reducer and Context --> - [Managing State](concepts/managing_state.md) - - [Hooks and Internal State](concepts/hooks.md) - [Global State](concepts/sharedstate.md) - [Error handling](concepts/errorhandling.md) - [Effects](concepts/effects.md) diff --git a/docs/guide/src/concepts/components.md b/docs/guide/src/concepts/components.md index d18a3c556..a5b824817 100644 --- a/docs/guide/src/concepts/components.md +++ b/docs/guide/src/concepts/components.md @@ -84,7 +84,7 @@ struct PostProps { And our render function: ```rust -fn Post((cx, props): Component) -> Element { +fn Post((cx, props): Scope) -> Element { cx.render(rsx!{ div { class: "post-container" VoteButton { @@ -120,7 +120,7 @@ struct VoteButtonProps { score: i32 } -fn VoteButton((cx, props): Component) -> Element { +fn VoteButton((cx, props): Scope) -> Element { cx.render(rsx!{ div { class: "votebutton" div { class: "arrow up" } @@ -145,7 +145,7 @@ struct TitleCardProps<'a> { title: &'a str, } -fn TitleCard<'a>((cx, props): Component<'a, TitleCardProps>) -> Element<'a> { +fn TitleCard<'a>((cx, props): Scope<'a, TitleCardProps>) -> Element<'a> { cx.render(rsx!{ h1 { "{props.title}" } }) @@ -174,7 +174,7 @@ function Component(props) { Because Dioxus needs to work with the rules of Rust it uses the `Context` object to maintain some internal bookkeeping. That's what the `Context` object is: a place for the component to store state, manage listeners, and allocate elements. Advanced users of Dioxus will want to learn how to properly leverage the `Context` object to build robust and performant extensions for Dioxus. ```rust -fn Post((cx /* <-- our Context object*/, props): Component) -> Element { +fn Post((cx /* <-- our Context object*/, props): Scope) -> Element { cx.render(rsx!{ }) } ``` diff --git a/docs/guide/src/concepts/conditional_rendering.md b/docs/guide/src/concepts/conditional_rendering.md index d5fc002d8..977f66597 100644 --- a/docs/guide/src/concepts/conditional_rendering.md +++ b/docs/guide/src/concepts/conditional_rendering.md @@ -26,7 +26,7 @@ struct AppProps { Now that we have a "logged_in" flag accessible in our props, we can render two different screens: ```rust -fn App((cx, props): Component) -> Element { +fn App((cx, props): Scope) -> Element { if props.logged_in { cx.render(rsx!{ DashboardScreen {} @@ -48,7 +48,7 @@ Rust provides us algebraic datatypes: enums that can contain values. Using the ` For instance, we could run a function that returns a Result: ```rust -fn App((cx, props): Component<()>) -> Element { +fn App((cx, props): Scope<()>) -> Element { match get_name() { Ok(name) => cx.render(rsx!( "Hello, {name}!" )), Err(err) => cx.render(rsx!( "Sorry, I don't know your name, because an error occurred: {err}" )), @@ -58,7 +58,7 @@ fn App((cx, props): Component<()>) -> Element { We can even match against values: ```rust -fn App((cx, props): Component<()>) -> Element { +fn App((cx, props): Scope<()>) -> Element { match get_name() { "jack" => cx.render(rsx!( "Hey Jack, how's Diane?" )), "diane" => cx.render(rsx!( "Hey Diana, how's Jack?" )), @@ -72,7 +72,7 @@ Do note: the `rsx!` macro returns a `Closure`, an anonymous function that has a To make patterns like these less verbose, the `rsx!` macro accepts an optional first argument on which it will call `render`. Our previous component can be shortened with this alternative syntax: ```rust -fn App((cx, props): Component<()>) -> Element { +fn App((cx, props): Scope<()>) -> Element { match get_name() { "jack" => rsx!(cx, "Hey Jack, how's Diane?" ), "diane" => rsx!(cx, "Hey Diana, how's Jack?" ), @@ -89,7 +89,7 @@ static App: Fc<()> = |(cx, props)| rsx!(cx, "hello world!"); Alternatively, for match statements, we can just return the builder itself and pass it into a final, single call to `cx.render`: ```rust -fn App((cx, props): Component<()>) -> Element { +fn App((cx, props): Scope<()>) -> Element { let greeting = match get_name() { "jack" => rsx!("Hey Jack, how's Diane?" ), "diane" => rsx!("Hey Diana, how's Jack?" ), diff --git a/docs/guide/src/concepts/event_handlers.md b/docs/guide/src/concepts/event_handlers.md index ee4560b1e..632511ec4 100644 --- a/docs/guide/src/concepts/event_handlers.md +++ b/docs/guide/src/concepts/event_handlers.md @@ -1 +1,11 @@ # Event handlers + +In the overview for this section, we mentioned how we can modify the state of our component by responding to user-generated events inside of event listeners. + +In this section, we'll talk more about event listeners: +- What events are available +- Handling event data +- Mutability in event listeners + +## Event Listeners + diff --git a/docs/guide/src/concepts/interactivity.md b/docs/guide/src/concepts/interactivity.md index 5e99d9853..f8e5e68e2 100644 --- a/docs/guide/src/concepts/interactivity.md +++ b/docs/guide/src/concepts/interactivity.md @@ -1 +1,185 @@ # Adding Interactivity + +So far, we've learned how to describe the structure and properties of our user interfaces. Unfortunately, they're static and quite a bit uninteresting. In this chapter, we're going to learn how to add interactivity through events, state, and tasks. + +## Primer on interactivity + +Before we get too deep into the mechanics of interactivity, we should first understand how Dioxus exactly chooses to handle user interaction and updates to your app. + +### What is state? + +Every app you'll ever build has some sort of information that needs to be rendered to the screen. Dioxus is responsible for translating your desired user interface to what is rendered to the screen. *You* are responsible for providing the content. + +The dynamic data in your user interface is called `State`. + +When you first launch your app with `dioxus::web::launch_with_props` you'll be providing the initial state. You need to declare the initial state *before* starting the app. + +```rust +fn main() { + // declare our initial state + let props = PostProps { + id: Uuid::new_v4(), + score: 10, + comment_count: 0, + post_time: std::time::Instant::now(), + url: String::from("dioxuslabs.com"), + title: String::from("Hello, world"), + original_poster: String::from("dioxus") + }; + + // start the render loop + dioxus::desktop::launch_with_props(Post, props); +} +``` + +When Dioxus renders your app, it will pass an immutable reference of `PostProps` to your `Post` component. Here, you can pass the state down into children. + +```rust +fn App((cx, props): Scope) -> Element { + cx.render(rsx!{ + Title { title: &props.title } + Score { score: &props.score } + // etc + }) +} +``` + +State in Dioxus follows a pattern called "one-way-data-flow." As your components create new components as their children, your app's structure will eventually grow into a tree where state gets passed down from the root component into "leaves" of the tree. + +You've probably seen the tree of UI components represented using an directed-acyclic-graph: + +![image](../images/component_tree.png) + +With Dioxus, your state will always flow down from parent components into child components. + +### How do I change my app's state? + +We've talked about the data flow of state, but we haven't yet talked about how to change that state dynamically. Dioxus provides a variety of ways to change the state of your app while it's running. + +For starters, we _could_ use the `update_root_props` method on the VirtualDom to provide an entirely new root state of your App. However, for most applications, you probably don't want to regenerate your entire app just to update some text or a flag. + +Instead, you'll want to store state internally in your components and let *that* flow down the tree. To store state in your components, you'll use something called a `hook`. Hooks are special functions that reserve a slot of state in your component's memory and provide some functionality to update that state. + +The most common hook you'll use for storing state is `use_state`. `use_state` provides a slot for some data that allows you to read and update the value without accidentally mutating it. + +```rust +fn App((cx, props): Scope<()>) -> Element { + let post = use_state(|| { + PostData { + id: Uuid::new_v4(), + score: 10, + comment_count: 0, + post_time: std::time::Instant::now(), + url: String::from("dioxuslabs.com"), + title: String::from("Hello, world"), + original_poster: String::from("dioxus") + } + }); + + cx.render(rsx!{ + Title { title: &post.title } + Score { score: &post.score } + // etc + }) +} +``` + +Whenever we have a new post that we want to render, we can call `set` on `post` and provide a new value: + +```rust +post.set(PostData { + id: Uuid::new_v4(), + score: 20, + comment_count: 0, + post_time: std::time::Instant::now(), + url: String::from("google.com"), + title: String::from("goodbye, world"), + original_poster: String::from("google") +}) +``` + +We'll dive deeper into how exactly these hooks work later. + +### When do I update my state? + +There are a few different approaches to choosing when to update your state. You can update your state in response to user-triggered events or asynchronously in some background task. + +### Updating state in listeners + +When responding to user-triggered events, we'll want to "listen" for an event on some element in our component. + +For example, let's say we provide a button to generate a new post. Whenever the user clicks the button, they get a new post. To achieve this functionality, we'll want to attach a function to the `on_click` method of `button`. Whenever the button is clicked, our function will run, and we'll get new Post data to work with. + +```rust +fn App((cx, props): Scope<()>) -> Element { + let post = use_state(|| PostData::new()); + + cx.render(rsx!{ + button { + on_click: move |_| post.set(PostData::random()) + "Generate a random post" + } + Post { props: &post } + }) +} +``` + +We'll dive much deeper into event listeners later. + +### Updating state asynchronously + +We can also update our state outside of event listeners with `tasks`. `Tasks` are asynchronous blocks of our component that have the ability to cleanly interact with values, hooks, and other data in the component. `Tasks` are one-shot - if they don't complete before the component is updated by another `.set` call, then they won't finish. + +We can use tasks in our components to build a tiny stopwatch that ticks every second. + +```rust + +fn App((cx, props): Scope<()>) -> Element { + let mut sec_elapsed = use_state(|| 0); + + cx.spawn_task(async move { + TimeoutFuture::from_ms(1000).await; + sec_elapsed += 1; + }); + + cx.render(rsx!{ + div { "Current stopwatch time: {sec_elapsed}" } + }) + +} +``` + +Using asynchronous code can be difficult! This is just scratching the surface of what's possible. We have an entire chapter on using async properly in your Dioxus Apps. + +### How do I tell Dioxus that my state changed? + +So far, we've only updated our state with `.set`. However, you might've noticed that we used `AddAssign` to increment the `sec_elapsed` value in our stopwatch example *without* calling set. This is because the `AddAssign` trait is implemented for `UseState` (the wrapper around our value returned from `use_state`). Under the hood, whenever you try to mutate our value through `UseState`, you're actually calling `.set` which informs Dioxus that _this_ component needs to be updated on the screen. + +Whenever you inform Dioxus that the component needs to be updated, it will "render" your component again, storing the previous and current Elements in memory. Dioxus will automatically figure out the differences between the old and the new and generate a list of edits that the renderer needs to apply to change what's on the screen. This process is called "diffing": + +![Diffing](../images/diffing.png) + +In React, the specifics of when a component gets re-rendered is somewhat blurry. With Dioxus, any component can mark itself as "dirty" through a method on `Context`: `needs_update`. In addition, any component can mark any _other_ component as dirty provided it knows the other component's ID with `needs_update_any`. + +With these building blocks, we can craft new hooks similar to `use_state` that let us easily tell Dioxus that new information is ready to be sent to the screen. + +### How do I update my state efficiently? + +In general, Dioxus should be plenty fast for most use cases. However, there are some rules you should consider following to ensure your apps are quick. + +- 1) **Don't call set—state _while rendering_**. This will cause Dioxus to unnecessarily re-check the component for updates. +- 2) **Break your state apart into smaller sections.** Hooks are explicitly designed to "unshackle" your state from the typical model-view-controller paradigm, making it easy to reuse useful bits of code with a single function. +- 3) **Move local state down**. Dioxus will need to re-check child components of your app if the root component is constantly being updated. You'll get best results if rapidly-changing state does not cause major re-renders. + +Don't worry - Dioxus is fast. But, if your app needs *extreme performance*, then take a look at the `Performance Tuning` in the `Advanced Guides` book. + + + +## Moving On + +This overview was a lot of information - but it doesn't tell you everything! + +In the next sections we'll go over: +- `use_state` in depth +- `use_ref` and other hooks +- Handling user input diff --git a/docs/guide/src/concepts/usestate.md b/docs/guide/src/concepts/usestate.md new file mode 100644 index 000000000..86a6b2efc --- /dev/null +++ b/docs/guide/src/concepts/usestate.md @@ -0,0 +1 @@ +# Fundamental Hooks and use_hook diff --git a/docs/guide/src/concepts/vnodes.md b/docs/guide/src/concepts/vnodes.md index 0bd5afc95..774b1bfba 100644 --- a/docs/guide/src/concepts/vnodes.md +++ b/docs/guide/src/concepts/vnodes.md @@ -129,7 +129,7 @@ rsx!( ) ``` -Note: the name of the custom attribute must match exactly what you want the renderer to output. All attributes defined as methods in `dioxus-html` follow the snake_case naming convention. However, they internally translate their snake_case convention to HTML's camelCase convention. +Note: the name of the custom attribute must match exactly what you want the renderer to output. All attributes defined as methods in `dioxus-html` follow the snake_case naming convention. However, they internally translate their snake_case convention to HTML's camelCase convention. When using custom attributes, make sure the name of the attribute exactly matches what the renderer is expecting. ## Listeners diff --git a/docs/guide/src/images/component_tree.png b/docs/guide/src/images/component_tree.png new file mode 100644 index 0000000000000000000000000000000000000000..d9692407350138e0b7597e8705e33f58a463357a GIT binary patch literal 3724 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 literal 0 HcmV?d00001 diff --git a/docs/guide/src/images/diffing.png b/docs/guide/src/images/diffing.png new file mode 100644 index 0000000000000000000000000000000000000000..4c243bc759085f24ada3be039cb763e1d59fc2f5 GIT binary patch literal 23486 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 Bge?F7 literal 0 HcmV?d00001 diff --git a/packages/core/src/context.rs b/packages/core/src/context.rs index 8e3389761..ca5d9cf25 100644 --- a/packages/core/src/context.rs +++ b/packages/core/src/context.rs @@ -65,6 +65,10 @@ impl<'src> Context<'src> { (self.scope.memoized_updater)() } + pub fn needs_update_any(&self, id: ScopeId) { + (self.scope.shared.schedule_any_immediate)(id) + } + /// Schedule an update for any component given its ScopeId. /// /// A component's ScopeId can be obtained from `use_hook` or the [`Context::scope_id`] method. @@ -101,11 +105,7 @@ impl<'src> Context<'src> { /// cx.render(lazy_tree) /// } ///``` - pub fn render( - self, - lazy_nodes: Option>, - // lazy_nodes: Option) -> VNode<'src> + '_>>, - ) -> Option> { + pub fn render(self, lazy_nodes: Option>) -> Option> { let bump = &self.scope.frames.wip_frame().bump; let factory = NodeFactory { bump }; lazy_nodes.map(|f| f.call(factory))