Rework Guide (#486)

* Move getting started to Guide

* Clean up summary and getting started

* Shorten intro by moving stuff to individual platform docs

* Make intro even shorter, summarize features

* Further cleanup; move development-related docs to separate section

* Make `guide` a crate. Turn code samples into examples so that we can check if they compile

* Rewrite "Describing the UI":

* Focus on RSX syntax (interactivity covered in later chapters); make sure samples are tested; concise language

* Move some "special attribute" samples to the `examples` directory

* Simplify introduction to components

* Simplify introduction to component props

* Document Prop features; add code samples

* Simplify component children docs

* Interactivity: better introduction to events

* Hooks: better introduction

* Remove outdated doc

* Introducs use_ref

* Simplify User Input chapter

* Document event handler props

* Meme editor example

* Meme editor walkthrough

* Add dark mode example

* Guide for context; dark mode example

* Guide: custom hooks

* Guide: conditional rendering

* Guide: rendering lists

* Guide: rendering lists + keys

* Move remaining infor from Reference to guide

* Delete reference book
This commit is contained in:
Reinis Mazeiks authored and GitHub committed 2022-07-07 08:50:36 +00:00
1 parent 92a8b7c75f
commit 6c323e9fc5
152 files changed
+2827 -5052

No files matched your search

+14 -66
View File
@@ -1,85 +1,33 @@
# UseFuture
When dealing with asynchronous code, you might need to wait for some action to complete before rendering your component. If you had to build this abstraction yourself, you'd probably end up with some `use_state` spaghetti code.
[`use_future`](https://docs.rs/dioxus-hooks/latest/dioxus_hooks/fn.use_future.html) lets you run an async closure, and provides you with its result.
One of the core hooks that Dioxus provides is `use_future` - a simple hook that lets you tap into a running task.
## Use case
The simplest use case of `use_future` is to prevent rendering until some asynchronous code has been completed. Dioxus doesn't currently have a library as sophisticated as React Query for prefetching tasks, but we can get some of the way there with `use_future`. In one of the Dioxus examples, we use `use_future` to download some search data before rendering the rest of the app:
For example, we can make an API request inside `use_future`:
```rust
fn app(cx: Scope) -> Element {
// set "breeds" to the current value of the future
let breeds = use_future(&cx, (), |_| async move {
reqwest::get("https://dog.ceo/api/breeds/list/all")
.await
.unwrap()
.json::<ListBreeds>()
.await
});
let status = match breeds.value() {
Some(Ok(val)) => "ready!",
Some(Err(err)) => "errored!",
None => "loading!",
}
}
{{#include ../../examples/use_future.rs:use_future}}
```
On first run, the code inside `use_future` will be submitted to the Dioxus scheduler once the component has rendered. Since there's no data ready when the component loads the first time, its "value" will be `None`.
The code inside `use_future` will be submitted to the Dioxus scheduler once the component has rendered.
However, once the future is finished, the component will be re-rendered and a new screen will be displayed - Ok or Err, depending on the outcome of our fetch.
We can use `.value()` to get the result of the future. On the first run, since there's no data ready when the component loads, its value will be `None`. However, once the future is finished, the component will be re-rendered and the value will now be `Some(...)`, containing the return value of the closure.
We can then render that result:
```rust
{{#include ../../examples/use_future.rs:render}}
```
## Restarting the Future
The example we showed above will only ever run once. What happens if some value changed on the server and we need to update our future's value?
The `UseFuture` handle provides a `restart` method. It can be used to execute the future again, producing a new value.
Well, the UseFuture handle provides a handy "restart" method. We can wire this up to a button or some other comparison code to get a regenerating future.
## Dependencies
```rust
fn app(cx: Scope) -> Element {
// set "breeds" to the current value of the future
let dog = use_future(&cx, (), |_| async move {
reqwest::get("https://dog.ceo/api/breeds/image/random")
.await
.unwrap()
.json::<RandomDog>()
.await
});
cx.render(match breeds.value() {
Some(Ok(val)) => rsx!(div {
img { src: "{val.message}"}
button {
onclick: move |_| dog.restart(),
"Click to fetch a new dog"
}
}),
Some(Err(err)) => rsx!("Failed to load dog"),
None => rsx!("Loading dog image!"),
})
}
```
## With Dependencies
We showed that UseFuture can be regenerated manually, but how can we automatically get it to update whenever some input value changes? This is where the "dependencies" tuple comes into play. We just need to add a value into our tuple argument and it'll be automatically cloned into our future when it starts.
Often, you will need to run the future again every time some value (e.g. a prop) changes. Rather than `.restart`ing it manually, you can provide a tuple of "dependencies" to the hook. It will automatically re-run the future when any of those dependencies change. Example:
```rust
#[inline_props]
fn RandomDog(cx: Scope, breed: String) -> Element {
let dog = use_future(&cx, (breed,), |(breed)| async move {
reqwest::get(format!("https://dog.ceo/api/breed/{breed}/images/random"))
.await
.unwrap()
.json::<RandomDog>()
.await
});
// some code as before
}
{{#include ../../examples/use_future.rs:dependency}}
```