Update docs to reflect changes in master (#670)
* work on updating docs to master version * more updates * more polishing * finish interactivity chapter * finish updating core guide * fix grammer mistakes and typos * more grammer fixes * add liveview guide * remove doc build * WIP custom renderer docs * add axum as dev-dependancy to guide * fix examples * fix overview example * use md book fork to fix compilation
This commit is contained in:
1 parent
a616a8fa9d
commit
cd4474cc4f
51 files changed
+870
-549
No files matched your search
@@ -8,16 +8,6 @@ The `use_future` and `use_coroutine` hooks are useful if you want to uncondition
|
||||
|
||||
> Note: `spawn` will always spawn a *new* future. You most likely don't want to call it on every render.
|
||||
|
||||
The future must be `'static` – so any values captured by the task cannot carry any references to `cx`, such as a `UseState`.
|
||||
|
||||
However, since you'll typically need a way to update the value of a hook, you can use `to_owned` to create a clone of the hook handle. You can then use that clone in the async closure.
|
||||
|
||||
To make this a bit less verbose, Dioxus exports the `to_owned!` macro which will create a binding as shown above, which can be quite helpful when dealing with many values.
|
||||
|
||||
```rust
|
||||
{{#include ../../../examples/spawn.rs:to_owned_macro}}
|
||||
```
|
||||
|
||||
Calling `spawn` will give you a `JoinHandle` which lets you cancel or pause the future.
|
||||
|
||||
## Spawning Tokio Tasks
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# Coroutines
|
||||
|
||||
Another good tool to keep in your async toolbox are coroutines. Coroutines are futures that can be manually stopped, started, paused, and resumed.
|
||||
Another tool in your async toolbox are coroutines. Coroutines are futures that can be manually stopped, started, paused, and resumed.
|
||||
|
||||
Like regular futures, code in a Dioxus coroutine will run until the next `await` point before yielding. This low-level control over asynchronous tasks is quite powerful, allowing for infinitely looping tasks like WebSocket polling, background timers, and other periodic actions.
|
||||
Like regular futures, code in a coroutine will run until the next `await` point before yielding. This low-level control over asynchronous tasks is quite powerful, allowing for infinitely looping tasks like WebSocket polling, background timers, and other periodic actions.
|
||||
|
||||
## `use_coroutine`
|
||||
|
||||
The basic setup for coroutines is the `use_coroutine` hook. Most coroutines we write will be polling loops using async/await.
|
||||
The `use_coroutine` hook allows you to create a coroutine. Most coroutines we write will be polling loops using async/await.
|
||||
|
||||
```rust
|
||||
fn app(cx: Scope) -> Element {
|
||||
@@ -50,11 +50,45 @@ if sync.is_running() {
|
||||
|
||||
This pattern is where coroutines are extremely useful – instead of writing all the complicated logic for pausing our async tasks like we would with JavaScript promises, the Rust model allows us to just not poll our future.
|
||||
|
||||
## Yielding Values
|
||||
|
||||
To yield values from a coroutine, simply bring in a `UseState` handle and set the value whenever your coroutine completes its work.
|
||||
|
||||
The future must be `'static` – so any values captured by the task cannot carry any references to `cx`, such as a `UseState`.
|
||||
|
||||
You can use [to_owned](https://doc.rust-lang.org/std/borrow/trait.ToOwned.html#tymethod.to_owned) to create a clone of the hook handle which can be moved into the async closure.
|
||||
|
||||
```rust
|
||||
let sync_status = use_state(cx, || Status::Launching);
|
||||
let sync_task = use_coroutine(cx, |rx: UnboundedReceiver<SyncAction>| {
|
||||
let sync_status = sync_status.to_owned();
|
||||
async move {
|
||||
loop {
|
||||
delay_ms(1000).await;
|
||||
sync_status.set(Status::Working);
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
To make this a bit less verbose, Dioxus exports the `to_owned!` macro which will create a binding as shown above, which can be quite helpful when dealing with many values.
|
||||
|
||||
```rust
|
||||
let sync_status = use_state(cx, || Status::Launching);
|
||||
let load_status = use_state(cx, || Status::Launching);
|
||||
let sync_task = use_coroutine(cx, |rx: UnboundedReceiver<SyncAction>| {
|
||||
to_owned![sync_status, load_status];
|
||||
async move {
|
||||
// ...
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## Sending Values
|
||||
|
||||
You might've noticed the `use_coroutine` closure takes an argument called `rx`. What is that? Well, a common pattern in complex apps is to handle a bunch of async code at once. With libraries like Redux Toolkit, managing multiple promises at once can be challenging and a common source of bugs.
|
||||
|
||||
With Coroutines, we have the opportunity to centralize our async logic. The `rx` parameter is an Unbounded Channel for code external to the coroutine to send data *into* the coroutine. Instead of looping on an external service, we can loop on the channel itself, processing messages from within our app without needing to spawn a new future. To send data into the coroutine, we would call "send" on the handle.
|
||||
With Coroutines, we can centralize our async logic. The `rx` parameter is an Channel that allows code external to the coroutine to send data *into* the coroutine. Instead of looping on an external service, we can loop on the channel itself, processing messages from within our app without needing to spawn a new future. To send data into the coroutine, we would call "send" on the handle.
|
||||
|
||||
|
||||
```rust
|
||||
@@ -103,7 +137,7 @@ async fn editor_service(rx: UnboundedReceiver<EditorCommand>) {
|
||||
}
|
||||
```
|
||||
|
||||
We can combine coroutines with Fermi to emulate Redux Toolkit's Thunk system with much less headache. This lets us store all of our app's state *within* a task and then simply update the "view" values stored in Atoms. It cannot be understated how powerful this technique is: we get all the perks of native Rust tasks with the optimizations and ergonomics of global state. This means your *actual* state does not need to be tied up in a system like Fermi or Redux – the only Atoms that need to exist are those that are used to drive the display/UI.
|
||||
We can combine coroutines with [Fermi](https://docs.rs/fermi/latest/fermi/index.html) to emulate Redux Toolkit's Thunk system with much less headache. This lets us store all of our app's state *within* a task and then simply update the "view" values stored in Atoms. It cannot be understated how powerful this technique is: we get all the perks of native Rust tasks with the optimizations and ergonomics of global state. This means your *actual* state does not need to be tied up in a system like Fermi or Redux – the only Atoms that need to exist are those that are used to drive the display/UI.
|
||||
|
||||
```rust
|
||||
static USERNAME: Atom<String> = |_| "default".to_string();
|
||||
@@ -152,27 +186,9 @@ async fn sync_service(mut rx: UnboundedReceiver<SyncAction>, atoms: AtomRoot) {
|
||||
}
|
||||
```
|
||||
|
||||
## Yielding Values
|
||||
|
||||
To yield values from a coroutine, simply bring in a `UseState` handle and set the value whenever your coroutine completes its work.
|
||||
|
||||
|
||||
```rust
|
||||
let sync_status = use_state(cx, || Status::Launching);
|
||||
let sync_task = use_coroutine(cx, |rx: UnboundedReceiver<SyncAction>| {
|
||||
to_owned![sync_status];
|
||||
async move {
|
||||
loop {
|
||||
delay_ms(1000).await;
|
||||
sync_status.set(Status::Working);
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## Automatic injection into the Context API
|
||||
|
||||
Coroutine handles are automatically injected through the context API. `use_coroutine_handle` with the message type as a generic can be used to fetch a handle.
|
||||
Coroutine handles are automatically injected through the context API. You can use the `use_coroutine_handle` hook with the message type as a generic to fetch a handle.
|
||||
|
||||
```rust
|
||||
fn Child(cx: Scope) -> Element {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
[`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.
|
||||
|
||||
For example, we can make an API request inside `use_future`:
|
||||
For example, we can make an API request (using [reqwest](https://docs.rs/reqwest/latest/reqwest/index.html)) inside `use_future`:
|
||||
|
||||
```rust
|
||||
{{#include ../../../examples/use_future.rs:use_future}}
|
||||
@@ -25,7 +25,7 @@ The `UseFuture` handle provides a `restart` method. It can be used to execute th
|
||||
|
||||
## Dependencies
|
||||
|
||||
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:
|
||||
Often, you will need to run the future again every time some value (e.g. a prop) changes. Rather than calling `restart` 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
|
||||
|
||||
Reference in new issue
Block a user