wip: some docs and suspense

This commit is contained in:
Jonathan Kelley committed 2021-11-23 15:53:57 -05:00
1 parent bab21a0aa1
commit 93d4b8ca7c
22 files changed
+210 -252

No files matched your search

+11 -10
View File
@@ -26,7 +26,7 @@ container.push(green_light);
container.push(yellow_light);
container.push(red_light);
container.onclick(move |_| {
container.set_onclick(move |_| {
if red_light.enabled() {
red_light.set_enabled(false);
green_light.set_enabled(true);
@@ -45,22 +45,23 @@ As the UI grows in scale, our logic to keep each element in the proper state wou
Instead, with Dioxus, we *declare* what we want our UI to look like:
```rust
let state = "red";
let mut state = use_state(cx, || "red");
rsx!(
cx.render(rsx!(
Container {
Light { color: "red", enabled: {state == "red"} }
Light { color: "yellow", enabled: {state == "yellow"} }
Light { color: "green", enabled: {state == "green"} }
onclick: |_| {
state = match state {
Light { color: "red", enabled: format_args!("{}", state == "red") }
Light { color: "yellow", enabled: format_args!("{}", state == "yellow") }
Light { color: "green", enabled: format_args!("{}", state == "green") }
onclick: move |_| {
state.set(match *state {
"green" => "yellow",
"yellow" => "red",
"red" => "green",
}
})
}
}
)
))
```
Remember: this concept is not new! Many frameworks are declarative - with React being the most popular. Declarative frameworks tend to be much more enjoyable to work with than imperative frameworks.
+5 -5
View File
@@ -84,7 +84,7 @@ struct PostProps {
And our render function:
```rust
fn Post((cx, props): Scope<PostProps>) -> Element {
fn Post(cx: Context, props: &PostProps) -> Element {
cx.render(rsx!{
div { class: "post-container"
VoteButton {
@@ -120,7 +120,7 @@ struct VoteButtonProps {
score: i32
}
fn VoteButton((cx, props): Scope<VoteButtonProps>) -> Element {
fn VoteButton(cx: Context, props: &VoteButtonProps) -> 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): Scope<'a, TitleCardProps>) -> Element<'a> {
fn TitleCard(cx: Context, props: &TitleCardProps) -> Element {
cx.render(rsx!{
h1 { "{props.title}" }
})
@@ -174,8 +174,8 @@ 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): Scope<PostProps>) -> Element {
cx.render(rsx!{ })
fn Post(cx: Context, props: &PostProps) -> Element {
cx.render(rsx!("hello"))
}
```
## Moving forward
@@ -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): Scope<AppProps>) -> Element {
fn App(cx: Context, props: &AppProps) -> 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): Scope<()>) -> Element {
fn App(cx: Context, props: &())-> 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): Scope<()>) -> Element {
We can even match against values:
```rust
fn App((cx, props): Scope<()>) -> Element {
fn App(cx: Context, props: &())-> Element {
match get_name() {
"jack" => cx.render(rsx!( "Hey Jack, how's Diane?" )),
"diane" => cx.render(rsx!( "Hey Diana, how's Jack?" )),
@@ -67,12 +67,12 @@ fn App((cx, props): Scope<()>) -> Element {
}
```
Do note: the `rsx!` macro returns a `Closure`, an anonymous function that has a unique type.
Do note: the `rsx!` macro returns a `Closure`, an anonymous function that has a unique type. To turn our `rsx!` into Elements, we need to call `cx.render`.
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): Scope<()>) -> Element {
fn App(cx: Context, props: &())-> Element {
match get_name() {
"jack" => rsx!(cx, "Hey Jack, how's Diane?" ),
"diane" => rsx!(cx, "Hey Diana, how's Jack?" ),
@@ -83,13 +83,13 @@ fn App((cx, props): Scope<()>) -> Element {
This syntax even enables us to write a one-line component:
```rust
static App: Fc<()> = |cx, props| rsx!(cx, "hello world!");
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): Scope<()>) -> Element {
fn App(cx: Context, props: &())-> Element {
let greeting = match get_name() {
"jack" => rsx!("Hey Jack, how's Diane?" ),
"diane" => rsx!("Hey Diana, how's Jack?" ),
+7 -7
View File
@@ -35,7 +35,7 @@ fn main() {
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<PostProps>) -> Element {
fn App(cx: Context, props: &PostProps) -> Element {
cx.render(rsx!{
Title { title: &props.title }
Score { score: &props.score }
@@ -63,8 +63,8 @@ Instead, you'll want to store state internally in your components and let *that*
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(|| {
fn App(cx: Context, props: &())-> Element {
let post = use_state(cx, || {
PostData {
id: Uuid::new_v4(),
score: 10,
@@ -111,8 +111,8 @@ When responding to user-triggered events, we'll want to "listen" for an event on
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());
fn App(cx: Context, props: &())-> Element {
let post = use_state(cx, || PostData::new());
cx.render(rsx!{
button {
@@ -134,8 +134,8 @@ We can use tasks in our components to build a tiny stopwatch that ticks every se
```rust
fn App((cx, props): Scope<()>) -> Element {
let mut sec_elapsed = use_state(|| 0);
fn App(cx: Context, props: &())-> Element {
let mut sec_elapsed = use_state(cx, || 0);
cx.spawn_task(async move {
TimeoutFuture::from_ms(1000).await;
+1 -1
View File
@@ -74,7 +74,7 @@ struct PostListProps<'a> {
Next, we're going to define our component:
```rust
fn App((cx, props): Component<PostList>) -> Element {
fn App(cx: Context, props: &PostList) -> Element {
// First, we create a new iterator by mapping the post array
let posts = props.posts.iter().map(|post| rsx!{
Post {
+53
View File
@@ -1 +1,54 @@
# Suspense
Suspense in Dioxus is enabled through placeholder nodes.
just a component that renders nodes into the placeholder after the future is finished?
in react, suspense is just completely pausing diffing while a
```rust
let n = use_suspense(cx || {
cx.render(rsx!{
Suspense {
prom: fut,
callback: || {}
}
})
})
suspense () {
let value = use_state();
if first_render {
push_task({
value.set(fut.await);
});
} else {
callback(value)
}
}
let name = fetch_name().await;
function ProfileDetails() {
// Try to read user info, although it might not have loaded yet
const user = resource.read();
return <h1>{user.name}</h1>;
}
fn ProfileDteails() {
let user = resource.suspend(cx, |l| rsx!("{l}"));
// waits for the resource to be ready and updates the placeholder with the tree
let name = resource.suspend_with(cx, |val| rsx!( div { "hello" "{user}" } ));
cx.render(rsx!(
div {
{user}
{name}
}
))
}
```
+1 -1
View File
@@ -107,7 +107,7 @@ To do this, we use the familiar struct-style syntax that Rust provides. Commas a
```rust
rsx!(
div {
hidden: true,
hidden: "true",
background_color: "blue",
class: "card color-{mycolor}"
}