mirror of
https://github.com/DioxusLabs/dioxus
synced 2024-11-10 06:34:20 +00:00
chore: rename ctx to cx
This commit is contained in:
parent
23c14078bb
commit
81382e7044
99 changed files with 789 additions and 664 deletions
|
@ -29,6 +29,7 @@ split-debuginfo = "unpacked"
|
|||
|
||||
|
||||
[dev-dependencies]
|
||||
futures = "0.3.15"
|
||||
# For the tide ssr examples
|
||||
# async-std = { version="1.9.0", features=["attributes"] }
|
||||
# tide = { version="0.16.0" }
|
||||
|
@ -45,6 +46,8 @@ split-debuginfo = "unpacked"
|
|||
# dioxus-webview = { path="./packages/webview", version="0.0.0" }
|
||||
# dioxus-hooks = { path="./packages/hooks", version="0.0.0" }
|
||||
rand = "0.8.4"
|
||||
serde = { version="1.0.126", features=["derive"] }
|
||||
surf = "2.2.0"
|
||||
|
||||
|
||||
[workspace]
|
||||
|
|
|
@ -82,8 +82,8 @@ fn main() {
|
|||
dioxus::web::start(App)
|
||||
}
|
||||
|
||||
fn App(ctx: Context<()>) -> VNode {
|
||||
ctx.render(rsx! {
|
||||
fn App(cx: Context<()>) -> VNode {
|
||||
cx.render(rsx! {
|
||||
div { "Hello, world!" }
|
||||
})
|
||||
}
|
||||
|
@ -108,8 +108,8 @@ fn main() {
|
|||
Finally, our app. Every component in Dioxus is a function that takes in a `Context` object and returns a `VNode`.
|
||||
|
||||
```rust
|
||||
fn App(ctx: Context<()>) -> VNode {
|
||||
ctx.render(rsx! {
|
||||
fn App(cx: Context<()>) -> VNode {
|
||||
cx.render(rsx! {
|
||||
div { "Hello, world!" }
|
||||
})
|
||||
};
|
||||
|
@ -119,7 +119,7 @@ In React, you'll save data between renders with hooks. However, hooks rely on gl
|
|||
|
||||
Next, we're greeted with the `rsx!` macro. This lets us add a custom DSL for declaratively building the structure of our app. The semantics of this macro are similar to that of JSX and HTML, though with a familiar Rust-y interface. The `html!` macro is also available for writing components with a JSX/HTML syntax.
|
||||
|
||||
The `rsx!` macro is lazy: it does not immediately produce elements or allocates, but rather builds a closure which can be rendered with `ctx.render`.
|
||||
The `rsx!` macro is lazy: it does not immediately produce elements or allocates, but rather builds a closure which can be rendered with `cx.render`.
|
||||
|
||||
Now, let's launch our app in a development server:
|
||||
|
||||
|
@ -135,7 +135,7 @@ If we wanted to golf a bit, we can shrink our hello-world even smaller:
|
|||
|
||||
```rust
|
||||
fn main() {
|
||||
dioxus::web::start(|ctx| ctx.render(diouxs::rsx!( div { "Hello, World!" } ))
|
||||
dioxus::web::start(|cx| cx.render(diouxs::rsx!( div { "Hello, World!" } ))
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
@ -12,8 +12,8 @@ You'll want to write RSX where you can, and in a future release we'll have a too
|
|||
|
||||
```rust
|
||||
#[fc]
|
||||
fn Example(ctx: Context, name: &str, pending: bool, count: i32 ) -> VNode {
|
||||
ctx.render(html! {
|
||||
fn Example(cx: Context, name: &str, pending: bool, count: i32 ) -> VNode {
|
||||
cx.render(html! {
|
||||
<div>
|
||||
<p> "Hello, {name}!" </p>
|
||||
<p> "Status: {pending}!" </p>
|
||||
|
@ -33,8 +33,8 @@ It's also a bit easier on the eyes 🙂.
|
|||
|
||||
```rust
|
||||
#[fc]
|
||||
fn Example(ctx: Context, name: &str, pending: bool, count: i32 ) -> VNode {
|
||||
ctx.render(rsx! {
|
||||
fn Example(cx: Context, name: &str, pending: bool, count: i32 ) -> VNode {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
p {"Hello, {name}!"}
|
||||
p {"Status: {pending}!"}
|
||||
|
@ -58,7 +58,7 @@ Commas are entirely optional, but might be useful to delineate between elements
|
|||
The `render` function provides an **extremely efficient** allocator for VNodes and text, so try not to use the `format!` macro in your components. Rust's default `ToString` methods pass through the global allocator, but all text in components is allocated inside a manually-managed Bump arena.
|
||||
|
||||
```rust
|
||||
static Example: FC<()> = |ctx| {
|
||||
static Example: FC<()> = |cx| {
|
||||
|
||||
let text = "example";
|
||||
|
||||
|
@ -67,11 +67,11 @@ static Example: FC<()> = |ctx| {
|
|||
"hello"
|
||||
};
|
||||
|
||||
let user_name = use_read_async(ctx, USERNAME);
|
||||
let title = ctx.suspend(user_name, |user_name| rsx!{ h1 { "Welcome back, {user_name}" } });
|
||||
let user_name = use_read_async(cx, USERNAME);
|
||||
let title = cx.suspend(user_name, |user_name| rsx!{ h1 { "Welcome back, {user_name}" } });
|
||||
|
||||
|
||||
ctx.render(rsx!{
|
||||
cx.render(rsx!{
|
||||
div {
|
||||
h1 { "Example" },
|
||||
|
||||
|
@ -125,9 +125,9 @@ static Example: FC<()> = |ctx| {
|
|||
// rsx! is lazy, and the underlying closures cannot have the same type
|
||||
// Rendering produces the VNode type
|
||||
{match rand::gen_range::<i32>(1..3) {
|
||||
1 => rsx!(in ctx, h1 { "big" })
|
||||
2 => rsx!(in ctx, h2 { "medium" })
|
||||
_ => rsx!(in ctx, h3 { "small" })
|
||||
1 => rsx!(in cx, h1 { "big" })
|
||||
2 => rsx!(in cx, h2 { "medium" })
|
||||
_ => rsx!(in cx, h3 { "small" })
|
||||
}}
|
||||
|
||||
// Optionals
|
||||
|
@ -138,12 +138,12 @@ static Example: FC<()> = |ctx| {
|
|||
|
||||
// Child nodes
|
||||
// Returns &[VNode]
|
||||
{ctx.children()}
|
||||
{cx.children()}
|
||||
|
||||
// Duplicating nodes
|
||||
// Clones the nodes by reference, so they are literally identical
|
||||
{{
|
||||
let node = rsx!(in ctx, h1{ "TopNode" });
|
||||
let node = rsx!(in cx, h1{ "TopNode" });
|
||||
(0..10).map(|_| node.clone())
|
||||
}}
|
||||
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
## Concurrency
|
||||
In Dioxus, VNodes are asynchronous and can their rendering can be paused at any time by awaiting a future. Hooks can combine this functionality with the Context and Subscription APIs to craft dynamic and efficient user experiences.
|
||||
|
||||
In Dioxus, VNodes are asynchronous and can their rendering can be paused at any time by awaiting a future. Hooks can combine this functionality with the Context and Subscription APIs to craft dynamic and efficient user experiences.
|
||||
|
||||
```rust
|
||||
fn user_data(ctx: Context<()>) -> VNode {
|
||||
fn user_data(cx: Context<()>) -> VNode {
|
||||
// Register this future as a task
|
||||
use_suspense(ctx, async {
|
||||
use_suspense(cx, async {
|
||||
// Continue on with the component as usual, waiting for data to arrive
|
||||
let Profile { name, birthday, .. } = fetch_data().await;
|
||||
html! {
|
||||
|
@ -16,4 +17,5 @@ fn user_data(ctx: Context<()>) -> VNode {
|
|||
})
|
||||
}
|
||||
```
|
||||
Asynchronous components are powerful but can also be easy to misuse as they pause rendering for the component and its children. Refer to the concurrent guide for information on how to best use async components.
|
||||
|
||||
Asynchronous components are powerful but can also be easy to misuse as they pause rendering for the component and its children. Refer to the concurrent guide for information on how to best use async components.
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
## Liveview
|
||||
|
||||
With the Context, Subscription, and Asynchronous APIs, we've built Dioxus Liveview: a coupling of frontend and backend to deliver user experiences that do not require dedicated API development. Instead of building and maintaining frontend-specific API endpoints, components can directly access databases, server caches, and other services directly from the component.
|
||||
|
||||
These set of features are still experimental. Currently, we're still working on making these components more ergonomic
|
||||
|
||||
```rust
|
||||
fn live_component(ctx: &Context<()>) -> VNode {
|
||||
fn live_component(cx: &Context<()>) -> VNode {
|
||||
use_live_component(
|
||||
ctx,
|
||||
cx,
|
||||
// Rendered via the client
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
|| html! { <div> {"Loading data from server..."} </div> },
|
||||
|
|
|
@ -8,8 +8,8 @@ struct MyProps {
|
|||
name: String
|
||||
}
|
||||
|
||||
fn Example(ctx: Context<MyProps>) -> VNode {
|
||||
html! { <div> "Hello {ctx.ctx.name}!" </div> }
|
||||
fn Example(cx: Context<MyProps>) -> VNode {
|
||||
html! { <div> "Hello {cx.cx.name}!" </div> }
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -18,14 +18,14 @@ Here, the `Context` object is used to access hook state, create subscriptions, a
|
|||
```rust
|
||||
// A very terse component!
|
||||
#[fc]
|
||||
fn Example(ctx: Context, name: String) -> VNode {
|
||||
fn Example(cx: Context, name: String) -> VNode {
|
||||
html! { <div> "Hello {name}!" </div> }
|
||||
}
|
||||
|
||||
// or
|
||||
|
||||
#[functional_component]
|
||||
static Example: FC = |ctx, name: String| html! { <div> "Hello {name}!" </div> };
|
||||
static Example: FC = |cx, name: String| html! { <div> "Hello {name}!" </div> };
|
||||
```
|
||||
|
||||
The final output of components must be a tree of VNodes. We provide an html macro for using JSX-style syntax to write these, though, you could use any macro, DSL, templating engine, or the constructors directly.
|
||||
|
|
|
@ -8,9 +8,9 @@ struct MyProps {
|
|||
name: String
|
||||
}
|
||||
|
||||
fn Example(ctx: Context<MyProps>) -> VNode {
|
||||
ctx.render(html! {
|
||||
<div> "Hello {ctx.name}!" </div>
|
||||
fn Example(cx: Context<MyProps>) -> VNode {
|
||||
cx.render(html! {
|
||||
<div> "Hello {cx.name}!" </div>
|
||||
})
|
||||
}
|
||||
```
|
||||
|
|
|
@ -11,7 +11,7 @@ This macro allows allows a classic struct definition to be embedded directly int
|
|||
```rust
|
||||
// Inlines and destructure props *automatically*
|
||||
#[functional_component]
|
||||
fn Example(ctx: Context, name: &str, pending: bool, count: i32 ) -> VNode {
|
||||
fn Example(cx: Context, name: &str, pending: bool, count: i32 ) -> VNode {
|
||||
html! {
|
||||
<div>
|
||||
<p> "Hello, {name}!" </p>
|
||||
|
@ -32,10 +32,10 @@ struct ExampleProps {
|
|||
count: i32
|
||||
};
|
||||
|
||||
fn Example(ctx: &mut Context<ExampleProps>) -> VNode {
|
||||
fn Example(cx: &mut Context<ExampleProps>) -> VNode {
|
||||
let ExampleProps {
|
||||
name, pending, count
|
||||
} = ctx.props;
|
||||
} = cx.props;
|
||||
|
||||
rsx! {
|
||||
<div>
|
||||
|
|
|
@ -12,8 +12,8 @@ You'll want to write RSX where you can, and in a future release we'll have a too
|
|||
|
||||
```rust
|
||||
#[fc]
|
||||
fn Example(ctx: Context, name: &str, pending: bool, count: i32 ) -> VNode {
|
||||
ctx.render(html! {
|
||||
fn Example(cx: Context, name: &str, pending: bool, count: i32 ) -> VNode {
|
||||
cx.render(html! {
|
||||
<div>
|
||||
<p> "Hello, {name}!" </p>
|
||||
<p> "Status: {pending}!" </p>
|
||||
|
@ -33,8 +33,8 @@ It's also a bit easier on the eyes 🙂.
|
|||
|
||||
```rust
|
||||
#[fc]
|
||||
fn Example(ctx: Context, name: &str, pending: bool, count: i32 ) -> VNode {
|
||||
ctx.render(rsx! {
|
||||
fn Example(cx: Context, name: &str, pending: bool, count: i32 ) -> VNode {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
p {"Hello, {name}!"}
|
||||
p {"Status: {pending}!"}
|
||||
|
@ -58,11 +58,11 @@ Commas are entirely optional, but might be useful to delineate between elements
|
|||
The `render` function provides an **extremely efficient** allocator for VNodes and text, so try not to use the `format!` macro in your components. Rust's default `ToString` methods pass through the global allocator, but all text in components is allocated inside a manually-managed Bump arena.
|
||||
|
||||
```rust
|
||||
static Example: FC<()> = |ctx| {
|
||||
static Example: FC<()> = |cx| {
|
||||
|
||||
let text = "example";
|
||||
|
||||
ctx.render(rsx!{
|
||||
cx.render(rsx!{
|
||||
div {
|
||||
h1 { "Example" },
|
||||
|
||||
|
@ -114,9 +114,9 @@ static Example: FC<()> = |ctx| {
|
|||
// rsx! is lazy, and the underlying closures cannot have the same type
|
||||
// Rendering produces the VNode type
|
||||
{match rand::gen_range::<i32>(1..3) {
|
||||
1 => rsx!(in ctx, h1 { "big" })
|
||||
2 => rsx!(in ctx, h2 { "medium" })
|
||||
_ => rsx!(in ctx, h3 { "small" })
|
||||
1 => rsx!(in cx, h1 { "big" })
|
||||
2 => rsx!(in cx, h2 { "medium" })
|
||||
_ => rsx!(in cx, h3 { "small" })
|
||||
}}
|
||||
|
||||
// Optionals
|
||||
|
@ -127,12 +127,12 @@ static Example: FC<()> = |ctx| {
|
|||
|
||||
// Child nodes
|
||||
// Returns &[VNode]
|
||||
{ctx.children()}
|
||||
{cx.children()}
|
||||
|
||||
// Duplicating nodes
|
||||
// Clones the nodes by reference, so they are literally identical
|
||||
{{
|
||||
let node = rsx!(in ctx, h1{ "TopNode" });
|
||||
let node = rsx!(in cx, h1{ "TopNode" });
|
||||
(0..10).map(|_| node.clone())
|
||||
}}
|
||||
|
||||
|
|
|
@ -1,17 +1,16 @@
|
|||
|
||||
```rust
|
||||
fn Example(ctx: &mut Context<()>) -> VNode {
|
||||
let service = use_combubulator(ctx);
|
||||
fn Example(cx: &mut Context<()>) -> VNode {
|
||||
let service = use_combubulator(cx);
|
||||
let Status { name, pending, count } = service.info();
|
||||
html! {
|
||||
<div>
|
||||
html! {
|
||||
<div>
|
||||
<p> "Hello, {name}!" </p>
|
||||
<p> "Status: {pending}!" </p>
|
||||
<p> "Count {count}!" </p>
|
||||
<button onclick=|_| service.update()>
|
||||
<button onclick=|_| service.update()>
|
||||
"Refresh services"
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
|
@ -1,47 +1,45 @@
|
|||
# Context API
|
||||
|
||||
|
||||
|
||||
```rust
|
||||
// Create contexts available to children
|
||||
// Only one context can be associated with any given component
|
||||
// This is known as "exposed state". Children can access this context,
|
||||
// but will not be automatically subscribed.
|
||||
fn ContextCreate(ctx: &mut Context<()>) -> VNode {
|
||||
let context = ctx.set_context(|| CustomContext::new());
|
||||
html! { <> {ctx.children()} </> }
|
||||
fn ContextCreate(cx: &mut Context<()>) -> VNode {
|
||||
let context = cx.set_context(|| CustomContext::new());
|
||||
html! { <> {cx.children()} </> }
|
||||
}
|
||||
|
||||
fn ContextRead(ctx: &mut Context<()>) -> VNode {
|
||||
fn ContextRead(cx: &mut Context<()>) -> VNode {
|
||||
// Panics if context is not available
|
||||
let some_ctx = ctx.get_context::<CustomContext>();
|
||||
let text = some_ctx.select("some_selector");
|
||||
let some_cx = cx.get_context::<CustomContext>();
|
||||
let text = some_cx.select("some_selector");
|
||||
html! { <div> "{text}" </div> }
|
||||
}
|
||||
|
||||
fn Subscription(ctx: &mut Context<()>) -> VNode {
|
||||
fn Subscription(cx: &mut Context<()>) -> VNode {
|
||||
// Open a "port" on the component for actions to trigger a re-evaluation
|
||||
let subscription = ctx.new_subscription();
|
||||
let subscription = cx.new_subscription();
|
||||
|
||||
// A looping timer - the effect is re-called on every re-evaluation
|
||||
use_async_effect(ctx, move || async {
|
||||
use_async_effect(cx, move || async {
|
||||
timer::new(2000).await;
|
||||
subscription.call();
|
||||
}, None);
|
||||
|
||||
// A one-shot timer, the deps don't change so the effect only happens once
|
||||
use_async_effect_deps(ctx, move || async {
|
||||
use_async_effect_deps(cx, move || async {
|
||||
timer::new(2000).await;
|
||||
subscription.call();
|
||||
}, ());
|
||||
}
|
||||
|
||||
// Mix subscriptions and context to make a simple Redux
|
||||
fn use_global_state<T: UserContextTrait>(ctx: &mut Context<()>) -> T {
|
||||
let some_ctx = ctx.get_context::<T>();
|
||||
let component_subscription = ctx.new_subscription();
|
||||
some_ctx.subscribe_component(component_subscription);
|
||||
some_ctx
|
||||
fn use_global_state<T: UserContextTrait>(cx: &mut Context<()>) -> T {
|
||||
let some_cx = cx.get_context::<T>();
|
||||
let component_subscription = cx.new_subscription();
|
||||
some_cx.subscribe_component(component_subscription);
|
||||
some_cx
|
||||
}
|
||||
|
||||
```
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
# Subscriptions
|
||||
# Subscriptions
|
||||
|
||||
Yew subscriptions are used to schedule update for components into the future. The `Context` object can create subscriptions:
|
||||
|
||||
```rust
|
||||
fn Component(ctx: Component<()>) -> VNode {
|
||||
let update = ctx.schedule();
|
||||
|
||||
fn Component(cx: Component<()>) -> VNode {
|
||||
let update = cx.schedule();
|
||||
|
||||
// Now, when the subscription is called, the component will be re-evaluted
|
||||
update.consume();
|
||||
}
|
||||
|
@ -13,16 +13,15 @@ fn Component(ctx: Component<()>) -> VNode {
|
|||
|
||||
Whenever a component's subscription is called, the component will then re-evaluated. You can consider the input properties of
|
||||
a component to be just another form of subscription. By default, the Dioxus component system automatically diffs a component's props
|
||||
when the parent function is called, and if the props are different, the child component's subscription is called.
|
||||
when the parent function is called, and if the props are different, the child component's subscription is called.
|
||||
|
||||
The subscription API exposes this functionality allowing hooks and state management solutions the ability to update components whenever
|
||||
some state or event occurs outside of the component. For instance, the `use_context` hook uses this to subscribe components that use a
|
||||
particular context.
|
||||
|
||||
|
||||
```rust
|
||||
fn use_context<I>(ctx: Context<T>) -> I {
|
||||
|
||||
fn use_context<I>(cx: Context<T>) -> I {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -32,6 +31,3 @@ fn use_context<I>(ctx: Context<T>) -> I {
|
|||
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -5,14 +5,15 @@ Concurrent mode provides a mechanism for building efficient asynchronous compone
|
|||
To make a component asynchronous, simply change its function signature to async.
|
||||
|
||||
```rust
|
||||
fn Example(ctx: Context<()>) -> Vnode {
|
||||
fn Example(cx: Context<()>) -> Vnode {
|
||||
rsx!{ <div> "Hello world!" </div> }
|
||||
}
|
||||
```
|
||||
|
||||
becomes
|
||||
|
||||
```rust
|
||||
async fn Example(ctx: Context<()>) -> Vnode {
|
||||
async fn Example(cx: Context<()>) -> Vnode {
|
||||
rsx!{ <div> "Hello world!" </div> }
|
||||
}
|
||||
```
|
||||
|
@ -20,7 +21,7 @@ async fn Example(ctx: Context<()>) -> Vnode {
|
|||
Now, logic in components can be awaited to delay updates of the component and its children. Like so:
|
||||
|
||||
```rust
|
||||
async fn Example(ctx: Context<()>) -> Vnode {
|
||||
async fn Example(cx: Context<()>) -> Vnode {
|
||||
let name = fetch_name().await;
|
||||
rsx!{ <div> "Hello {name}" </div> }
|
||||
}
|
||||
|
@ -30,7 +31,7 @@ async fetch_name() -> String {
|
|||
}
|
||||
```
|
||||
|
||||
This component will only schedule its render once the fetch is complete. However, we *don't* recommend using async/await directly in your components.
|
||||
This component will only schedule its render once the fetch is complete. However, we _don't_ recommend using async/await directly in your components.
|
||||
|
||||
Async is a notoriously challenging yet rewarding tool for efficient tools. If not careful, locking and unlocking shared aspects of the component's context can lead to data races and panics. If a shared resource is locked while the component is awaiting, then other components can be locked or panic when trying to access the same resource. These rules are especially important when references to shared global state are accessed using the context object's lifetime. If mutable references to data captured immutably by the context are taken, then the component will panic, and cause confusion.
|
||||
|
||||
|
@ -39,7 +40,7 @@ Instead, we suggest using hooks and future combinators that can safely utilize t
|
|||
As part of our Dioxus hooks crate, we provide a data loader hook which pauses a component until its async dependencies are ready. This caches requests, reruns the fetch if dependencies have changed, and provides the option to render something else while the component is loading.
|
||||
|
||||
```rust
|
||||
async fn ExampleLoader(ctx: Context<()>) -> Vnode {
|
||||
async fn ExampleLoader(cx: Context<()>) -> Vnode {
|
||||
/*
|
||||
Fetch, pause the component from rendering at all.
|
||||
|
||||
|
@ -49,8 +50,8 @@ async fn ExampleLoader(ctx: Context<()>) -> Vnode {
|
|||
This API stores the result on the Context object, so the loaded data is taken as reference.
|
||||
*/
|
||||
let name: &Result<SomeStructure> = use_fetch_data("http://example.com/json", ())
|
||||
.place_holder(|ctx| rsx!{<div> "loading..." </div>})
|
||||
.delayed_place_holder(1000, |ctx| rsx!{ <div> "still loading..." </div>})
|
||||
.place_holder(|cx| rsx!{<div> "loading..." </div>})
|
||||
.delayed_place_holder(1000, |cx| rsx!{ <div> "still loading..." </div>})
|
||||
.await;
|
||||
|
||||
match name {
|
||||
|
@ -60,14 +61,11 @@ async fn ExampleLoader(ctx: Context<()>) -> Vnode {
|
|||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
```rust
|
||||
async fn Example(ctx: Context<()>) -> VNode {
|
||||
async fn Example(cx: Context<()>) -> VNode {
|
||||
// Diff this set between the last set
|
||||
// Check if we have any outstanding tasks?
|
||||
//
|
||||
//
|
||||
// Eventually, render the component into the VDOM when the future completes
|
||||
<div>
|
||||
<Example />
|
||||
|
@ -79,6 +77,6 @@ async fn Example(ctx: Context<()>) -> VNode {
|
|||
<Suspense placeholder={html!{<div>"Loading"</div>}}>
|
||||
<Example />
|
||||
</Suspense>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
```
|
||||
|
|
|
@ -2,13 +2,13 @@
|
|||
|
||||
Dioxus differs slightly from other UI virtual doms in some subtle ways due to its memory allocator.
|
||||
|
||||
One important aspect to understand is how props are passed down from parent components to children. All "components" (custom user-made UI elements) are tightly allocated together in an arena. However, because props and hooks are generically typed, they are casted to any and allocated on the heap - not in the arena with the components.
|
||||
One important aspect to understand is how props are passed down from parent components to children. All "components" (custom user-made UI elements) are tightly allocated together in an arena. However, because props and hooks are generically typed, they are casted to any and allocated on the heap - not in the arena with the components.
|
||||
|
||||
With this system, we try to be more efficient when leaving the component arena and entering the heap. By default, props are memoized between renders using COW and context. This makes props comparisons fast - done via ptr comparisons on the cow pointer. Because memoization is done by default, parent re-renders will *not* cascade to children if the child's props did not change.
|
||||
With this system, we try to be more efficient when leaving the component arena and entering the heap. By default, props are memoized between renders using COW and context. This makes props comparisons fast - done via ptr comparisons on the cow pointer. Because memoization is done by default, parent re-renders will _not_ cascade to children if the child's props did not change.
|
||||
|
||||
https://dmitripavlutin.com/use-react-memo-wisely/
|
||||
|
||||
This behavior is defined as an implicit attribute to user components. When in React land you might wrap a component is `react.memo`, Dioxus components are automatically memoized via an implicit attribute. You can manually configure this behavior on any component with "nomemo" to disable memoization.
|
||||
This behavior is defined as an implicit attribute to user components. When in React land you might wrap a component is `react.memo`, Dioxus components are automatically memoized via an implicit attribute. You can manually configure this behavior on any component with "nomemo" to disable memoization.
|
||||
|
||||
```rust
|
||||
fn test() -> VNode {
|
||||
|
@ -21,9 +21,9 @@ fn test() -> VNode {
|
|||
}
|
||||
}
|
||||
|
||||
static TestComponent: FC<()> = |ctx| html!{<div>"Hello world"</div>};
|
||||
static TestComponent: FC<()> = |cx| html!{<div>"Hello world"</div>};
|
||||
|
||||
static TestComponent: FC<()> = |ctx| {
|
||||
static TestComponent: FC<()> = |cx| {
|
||||
let g = "BLAH";
|
||||
html! {
|
||||
<div> "Hello world" </div>
|
||||
|
@ -31,7 +31,7 @@ static TestComponent: FC<()> = |ctx| {
|
|||
};
|
||||
|
||||
#[functional_component]
|
||||
static TestComponent: FC<{ name: String }> = |ctx| html! { <div> "Hello {name}" </div> };
|
||||
static TestComponent: FC<{ name: String }> = |cx| html! { <div> "Hello {name}" </div> };
|
||||
```
|
||||
|
||||
## Why this behavior?
|
||||
|
@ -41,8 +41,8 @@ static TestComponent: FC<{ name: String }> = |ctx| html! { <div> "Hello {name}"
|
|||
Take a component likes this:
|
||||
|
||||
```rust
|
||||
fn test(ctx: Context<()>) -> VNode {
|
||||
let Bundle { alpha, beta, gamma } = use_context::<SomeContext>(ctx);
|
||||
fn test(cx: Context<()>) -> VNode {
|
||||
let Bundle { alpha, beta, gamma } = use_context::<SomeContext>(cx);
|
||||
html! {
|
||||
<div>
|
||||
<Component name=alpha />
|
||||
|
@ -53,4 +53,4 @@ fn test(ctx: Context<()>) -> VNode {
|
|||
}
|
||||
```
|
||||
|
||||
While the contents of the destructued bundle might change, not every child component will need to be re-rendered.
|
||||
While the contents of the destructued bundle might change, not every child component will need to be re-rendered.
|
||||
|
|
|
@ -4,10 +4,10 @@ use dioxus_core::prelude::*;
|
|||
|
||||
fn main() {}
|
||||
|
||||
static Example: FC<()> = |ctx| {
|
||||
let (name, set_name) = use_state(&ctx, || "...?");
|
||||
static Example: FC<()> = |cx| {
|
||||
let (name, set_name) = use_state(&cx, || "...?");
|
||||
|
||||
ctx.render(rsx!(
|
||||
cx.render(rsx!(
|
||||
div {
|
||||
h1 { "Hello, {name}" }
|
||||
// look ma - we can rsx! and html! together
|
||||
|
@ -17,8 +17,8 @@ static Example: FC<()> = |ctx| {
|
|||
};
|
||||
|
||||
pub fn render<'src, 'a, F: for<'b> FnOnce(&'b NodeCtx<'src>) -> VNode<'src> + 'src + 'a, P>(
|
||||
ctx: &'a Context<'src, P>,
|
||||
cx: &'a Context<'src, P>,
|
||||
lazy_nodes: LazyNodes<'src, F>,
|
||||
) -> VNode<'src> {
|
||||
ctx.render(lazy_nodes)
|
||||
cx.render(lazy_nodes)
|
||||
}
|
||||
|
|
|
@ -7,12 +7,12 @@
|
|||
fn main() {}
|
||||
use dioxus::prelude::*;
|
||||
|
||||
pub static ExampleReducer: FC<()> = |ctx| {
|
||||
let (state, reduce) = use_reducer(&ctx, PlayerState::new, PlayerState::reduce);
|
||||
pub static ExampleReducer: FC<()> = |cx| {
|
||||
let (state, reduce) = use_reducer(&cx, PlayerState::new, PlayerState::reduce);
|
||||
|
||||
let is_playing = state.is_playing();
|
||||
|
||||
ctx.render(rsx! {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
h1 {"Select an option"}
|
||||
h3 {"The radio is... {is_playing}!"}
|
||||
|
|
|
@ -190,7 +190,7 @@ pub struct TallerProps {
|
|||
}
|
||||
|
||||
/// This component is taller than most :)
|
||||
pub fn Taller(ctx: Context<TallerProps>) -> VNode {
|
||||
pub fn Taller(cx: Context<TallerProps>) -> VNode {
|
||||
let b = true;
|
||||
todo!()
|
||||
}
|
||||
|
|
52
examples/suspense.rs
Normal file
52
examples/suspense.rs
Normal file
|
@ -0,0 +1,52 @@
|
|||
//! Example: Suspense
|
||||
//! -----------------
|
||||
//! This example shows how the "use_fetch" hook is built on top of Dioxus' "suspense" API. Suspense enables components
|
||||
//! to wait on futures to complete before rendering the result into VNodes. These VNodes are immediately available in a
|
||||
//! "suspended" fashion and will automatically propogate to the UI when the future completes.
|
||||
//!
|
||||
//! Note that if your component updates or receives new props while it is awating the result, the future will be dropped
|
||||
//! and all work will stop. In this example, we store the future in a hook so we can always resume it.
|
||||
|
||||
use dioxus::prelude::*;
|
||||
|
||||
fn main() {}
|
||||
|
||||
#[derive(serde::Deserialize)]
|
||||
struct DogApi {
|
||||
message: String,
|
||||
}
|
||||
const ENDPOINT: &str = "https://dog.ceo/api/breeds/image/random";
|
||||
|
||||
pub static App: FC<()> = |cx| {
|
||||
let doggo = use_fetch(&cx, ENDPOINT, |cx, res: surf::Result<DogApi>| match res {
|
||||
Ok(res) => rsx!(in cx, img { src: "{res.message}"}),
|
||||
Err(_) => rsx!(in cx, p { "Failed to load doggo :("}),
|
||||
});
|
||||
|
||||
cx.render(rsx!(
|
||||
div {
|
||||
h1 {"Waiting for a doggo..."}
|
||||
{doggo}
|
||||
}
|
||||
))
|
||||
};
|
||||
|
||||
fn use_fetch<'a, T: serde::de::DeserializeOwned + 'static>(
|
||||
cx: &impl Scoped<'a>,
|
||||
url: &str,
|
||||
g: impl FnOnce(dioxus_core::virtual_dom::SuspendedContext, surf::Result<T>) -> VNode<'a> + 'a,
|
||||
) -> VNode<'a> {
|
||||
use futures::Future;
|
||||
use futures::FutureExt;
|
||||
use std::pin::Pin;
|
||||
|
||||
// essentially we're doing a "use_effect" but with no dependent props
|
||||
let doggo_promise: &'a mut Pin<Box<dyn Future<Output = surf::Result<T>> + Send + 'static>> = cx
|
||||
.use_hook(
|
||||
move || surf::get(url).recv_json::<T>().boxed(),
|
||||
// just pass the future through
|
||||
|p| p,
|
||||
|_| (),
|
||||
);
|
||||
cx.suspend(doggo_promise, g)
|
||||
}
|
|
@ -17,7 +17,7 @@ Originally the syntax of the FC macro was meant to look like:
|
|||
|
||||
```rust
|
||||
#[fc]
|
||||
fn example(ctx: &Context<{ name: String }>) -> VNode {
|
||||
fn example(cx: &Context<{ name: String }>) -> VNode {
|
||||
html! { <div> "Hello, {name}!" </div> }
|
||||
}
|
||||
```
|
||||
|
@ -26,7 +26,7 @@ fn example(ctx: &Context<{ name: String }>) -> VNode {
|
|||
|
||||
```rust
|
||||
#[fc]
|
||||
fn example(ctx: &Context, name: String) -> VNode {
|
||||
fn example(cx: &Context, name: String) -> VNode {
|
||||
html! { <div> "Hello, {name}!" </div> }
|
||||
}
|
||||
```
|
||||
|
@ -53,7 +53,7 @@ impl FunctionProvider for SomeComponent {
|
|||
pub type SomeComponent = FunctionComponent<function_name>;
|
||||
```
|
||||
|
||||
By default, the underlying component is defined as a "functional" implementation of the `Component` trait with all the lifecycle methods. In Dioxus, we don't allow components as structs, and instead take a "hooks-only" approach. However, we still need ctx. To get these without dealing with traits, we just assume functional components are modules. This lets the macros assume an FC is a module, and `FC::Props` is its props and `FC::component` is the component. Yew's method does a similar thing, but with associated types on traits.
|
||||
By default, the underlying component is defined as a "functional" implementation of the `Component` trait with all the lifecycle methods. In Dioxus, we don't allow components as structs, and instead take a "hooks-only" approach. However, we still need cx. To get these without dealing with traits, we just assume functional components are modules. This lets the macros assume an FC is a module, and `FC::Props` is its props and `FC::component` is the component. Yew's method does a similar thing, but with associated types on traits.
|
||||
|
||||
Perhaps one day we might use traits instead.
|
||||
|
||||
|
@ -71,7 +71,7 @@ mod Example {
|
|||
name: String
|
||||
}
|
||||
|
||||
fn component(ctx: &Context<Props>) -> VNode {
|
||||
fn component(cx: &Context<Props>) -> VNode {
|
||||
html! { <div> "Hello, {name}!" </div> }
|
||||
}
|
||||
}
|
||||
|
@ -84,7 +84,7 @@ struct Props {
|
|||
name: String
|
||||
}
|
||||
|
||||
fn component(ctx: &Context<Props>) -> VNode {
|
||||
fn component(cx: &Context<Props>) -> VNode {
|
||||
html! { <div> "Hello, {name}!" </div> }
|
||||
}
|
||||
```
|
||||
|
@ -93,7 +93,7 @@ These definitions might be ugly, but the fc macro cleans it all up. The fc macro
|
|||
|
||||
```rust
|
||||
#[fc]
|
||||
fn example(ctx: &Context, name: String) -> VNode {
|
||||
fn example(cx: &Context, name: String) -> VNode {
|
||||
html! { <div> "Hello, {name}!" </div> }
|
||||
}
|
||||
|
||||
|
@ -105,7 +105,7 @@ mod Example {
|
|||
struct Props {
|
||||
name: String
|
||||
}
|
||||
fn component(ctx: &Context<Props>) -> VNode {
|
||||
fn component(cx: &Context<Props>) -> VNode {
|
||||
html! { <div> "Hello, {name}!" </div> }
|
||||
}
|
||||
}
|
||||
|
@ -119,19 +119,19 @@ From a certain perspective, live components are simply server-side-rendered comp
|
|||
|
||||
```rust
|
||||
#[fc]
|
||||
static LiveFc: FC = |ctx, refresh_handler: impl FnOnce| {
|
||||
static LiveFc: FC = |cx, refresh_handler: impl FnOnce| {
|
||||
// Grab the "live context"
|
||||
let live_context = ctx.use_context::<LiveContext>();
|
||||
let live_context = cx.use_context::<LiveContext>();
|
||||
|
||||
// Ensure this component is registered as "live"
|
||||
live_context.register_scope();
|
||||
|
||||
// send our props to the live context and get back a future
|
||||
let vnodes = live_context.request_update(ctx);
|
||||
let vnodes = live_context.request_update(cx);
|
||||
|
||||
// Suspend the rendering of this component until the vnodes are finished arriving
|
||||
// Render them once available
|
||||
ctx.suspend(async move {
|
||||
cx.suspend(async move {
|
||||
let output = vnodes.await;
|
||||
|
||||
// inject any listener handles (ie button clicks, views, etc) to the parsed nodes
|
||||
|
@ -153,13 +153,13 @@ Notice that LiveComponent receivers (the client-side interpretation of a LiveCom
|
|||
The `VNodeTree` type is a very special type that allows VNodes to be created using a pluggable allocator. The html! macro creates something that looks like:
|
||||
|
||||
```rust
|
||||
static Example: FC<()> = |ctx| {
|
||||
static Example: FC<()> = |cx| {
|
||||
html! { <div> "blah" </div> }
|
||||
};
|
||||
|
||||
// expands to...
|
||||
|
||||
static Example: FC<()> = |ctx| {
|
||||
static Example: FC<()> = |cx| {
|
||||
// This function converts a Fn(allocator) -> VNode closure to a VNode struct that will later be evaluated.
|
||||
html_macro_to_vnodetree(move |allocator| {
|
||||
let mut node0 = allocator.alloc(VElement::div);
|
||||
|
@ -170,7 +170,7 @@ static Example: FC<()> = |ctx| {
|
|||
};
|
||||
```
|
||||
|
||||
At runtime, the new closure is created that captures references to `ctx`. Therefore, this closure can only be evaluated while `ctx` is borrowed and in scope. However, this closure can only be evaluated with an `allocator`. Currently, the global and Bumpalo allocators are available, though in the future we will add support for creating a VDom with any allocator or arena system (IE Jemalloc, wee-alloc, etc). The intention here is to allow arena allocation of VNodes (no need to box nested VNodes). Between diffing phases, the arena will be overwritten as old nodes are replaced with new nodes. This saves allocation time and enables bump allocators.
|
||||
At runtime, the new closure is created that captures references to `cx`. Therefore, this closure can only be evaluated while `cx` is borrowed and in scope. However, this closure can only be evaluated with an `allocator`. Currently, the global and Bumpalo allocators are available, though in the future we will add support for creating a VDom with any allocator or arena system (IE Jemalloc, wee-alloc, etc). The intention here is to allow arena allocation of VNodes (no need to box nested VNodes). Between diffing phases, the arena will be overwritten as old nodes are replaced with new nodes. This saves allocation time and enables bump allocators.
|
||||
|
||||
## Context and lifetimes
|
||||
|
||||
|
@ -216,8 +216,8 @@ struct ExampleContext {
|
|||
items: Vec<String>
|
||||
}
|
||||
|
||||
fn Example<'src>(ctx: Context<'src, ()>) -> VNode<'src> {
|
||||
let val: &'b ContextGuard<ExampleContext> = (&'b ctx).use_context(|context: &'other ExampleContext| {
|
||||
fn Example<'src>(cx: Context<'src, ()>) -> VNode<'src> {
|
||||
let val: &'b ContextGuard<ExampleContext> = (&'b cx).use_context(|context: &'other ExampleContext| {
|
||||
// always select the last element
|
||||
context.items.last()
|
||||
});
|
||||
|
@ -225,7 +225,7 @@ fn Example<'src>(ctx: Context<'src, ()>) -> VNode<'src> {
|
|||
let handler1 = move |_| println!("Value is {}", val); // deref coercion performed here for printing
|
||||
let handler2 = move |_| println!("Value is {}", val); // deref coercion performed here for printing
|
||||
|
||||
ctx.render(html! {
|
||||
cx.render(html! {
|
||||
<div>
|
||||
<button onclick={handler1}> "Echo value with h1" </button>
|
||||
<button onclick={handler2}> "Echo value with h2" </button>
|
||||
|
@ -313,9 +313,9 @@ Here's how react does it:
|
|||
Any "dirty" node causes an entire subtree render. Calling "setState" at the very top will cascade all the way down. This is particularly bad for this component design:
|
||||
|
||||
```rust
|
||||
static APP: FC<()> = |ctx| {
|
||||
static APP: FC<()> = |cx| {
|
||||
let title = use_context(Title);
|
||||
ctx.render(html!{
|
||||
cx.render(html!{
|
||||
<div>
|
||||
<h1> "{title}"</h1>
|
||||
<HeavyList /> // VComponent::new(|| (FC, PropsForFc)) -> needs a context to immediately update the component's props imperatively? store the props in a box on bump? store the props on the child?
|
||||
|
@ -334,8 +334,8 @@ static APP: FC<()> = |ctx| {
|
|||
</div>
|
||||
})
|
||||
};
|
||||
static HEAVY_LIST: FC<()> = |ctx| {
|
||||
ctx.render({
|
||||
static HEAVY_LIST: FC<()> = |cx| {
|
||||
cx.render({
|
||||
{0.100.map(i => <BigElement >)}
|
||||
})
|
||||
};
|
||||
|
@ -348,7 +348,7 @@ An update to the use_context subscription will mark the node as dirty. The node
|
|||
The FC layout was altered to make life easier for us inside the VirtualDom. The "view" function returns an unbounded VNode object. Calling the "view" function is unsafe under the hood, but prevents lifetimes from leaking out of the function call. Plus, it's easier to write. Because there are no lifetimes on the output (occur purely under the hood), we can escape needing to annotate them.
|
||||
|
||||
```rust
|
||||
fn component(ctx: Context, props: &Props) -> VNode {
|
||||
fn component(cx: Context, props: &Props) -> VNode {
|
||||
|
||||
}
|
||||
```
|
||||
|
@ -378,7 +378,7 @@ struct Props {
|
|||
|
||||
}
|
||||
|
||||
static Component: FC<Props> = |ctx| {
|
||||
static Component: FC<Props> = |cx| {
|
||||
|
||||
}
|
||||
```
|
||||
|
@ -387,7 +387,7 @@ or
|
|||
|
||||
```rust
|
||||
#[fc]
|
||||
static Component: FC = |ctx, name: &str| {
|
||||
static Component: FC = |cx, name: &str| {
|
||||
|
||||
}
|
||||
```
|
||||
|
@ -406,8 +406,8 @@ enum Patch {
|
|||
```
|
||||
|
||||
```rust
|
||||
let node_ref = use_node_ref(&ctx);
|
||||
use_effect(&ctx, || {
|
||||
let node_ref = use_node_ref(&cx);
|
||||
use_effect(&cx, || {
|
||||
|
||||
}, []);
|
||||
div { ref: node_ref,
|
||||
|
|
|
@ -53,23 +53,23 @@ This atom of state is initialized with a value of `"Green"`. The atom that is re
|
|||
This is then later used in components like so:
|
||||
|
||||
```rust
|
||||
fn App(ctx: Context<()>) -> VNode {
|
||||
fn App(cx: Context<()>) -> VNode {
|
||||
// The Atom root must be initialized at the top of the application before any use_Atom hooks
|
||||
dirac::intialize_root(&ctx, |_| {});
|
||||
dirac::intialize_root(&cx, |_| {});
|
||||
|
||||
let color = dirac::use_read(&ctx, &LightColor);
|
||||
let color = dirac::use_read(&cx, &LightColor);
|
||||
|
||||
ctx.render(rsx!( h1 {"Color of light: {color}"} ))
|
||||
cx.render(rsx!( h1 {"Color of light: {color}"} ))
|
||||
}
|
||||
```
|
||||
|
||||
Atoms are considered "Writable" objects since any consumer may also set the Atom's value with their own:
|
||||
|
||||
```rust
|
||||
fn App(ctx: Context<()>) -> VNode {
|
||||
let color = dirac::use_read(&ctx, &LightColor);
|
||||
let set_color = dirac::use_write(&ctx, &LightColor);
|
||||
ctx.render(rsx!(
|
||||
fn App(cx: Context<()>) -> VNode {
|
||||
let color = dirac::use_read(&cx, &LightColor);
|
||||
let set_color = dirac::use_write(&cx, &LightColor);
|
||||
cx.render(rsx!(
|
||||
h1 { "Color: {color}" }
|
||||
button { onclick: move |_| set_color("red"), "red" }
|
||||
button { onclick: move |_| set_color("yellow"), "yellow" }
|
||||
|
@ -81,9 +81,9 @@ fn App(ctx: Context<()>) -> VNode {
|
|||
"Reading" a value with use_read subscribes that component to any changes to that value while "Writing" a value does not. It's a good idea to use `write-only` whenever it makes sense to prevent unnecessary evaluations. Both `read` and `write` may be combined together to provide a `use_state` style hook.
|
||||
|
||||
```rust
|
||||
fn App(ctx: Context<()>) -> VNode {
|
||||
let (color, set_color) = dirac::use_read_write(&ctx, &Light);
|
||||
ctx.render(rsx!(
|
||||
fn App(cx: Context<()>) -> VNode {
|
||||
let (color, set_color) = dirac::use_read_write(&cx, &Light);
|
||||
cx.render(rsx!(
|
||||
h1 { "Color: {color}" }
|
||||
button { onclick: move |_| set_color("red"), "red" }
|
||||
))
|
||||
|
@ -154,9 +154,9 @@ const CloudRatings: AtomFamily<&str, i32> = |api| {
|
|||
Whenever you `select` on a `Family`, the ID of the entry is tracked. Other subscribers will only be updated if they too select the same family with the same key and that value is updated. Otherwise, these subscribers will never re-render on an "insert", "remove", or "update" of the collection. You could easily implement this yourself with Atoms, immutable datastructures, and selectors, but our implementation is more efficient and first-class.
|
||||
|
||||
```rust
|
||||
fn App(ctx: Context<()>) -> VNode {
|
||||
let (rating, set_rating) = dirac::use_read_write(ctx, CloudRatings.select("AWS"));
|
||||
ctx.render(rsx!(
|
||||
fn App(cx: Context<()>) -> VNode {
|
||||
let (rating, set_rating) = dirac::use_read_write(cx, CloudRatings.select("AWS"));
|
||||
cx.render(rsx!(
|
||||
h1 { "AWS rating: {rating}" }
|
||||
button { onclick: move |_| set_rating((rating + 1) % 5), "incr" }
|
||||
))
|
||||
|
|
|
@ -28,12 +28,12 @@ impl TitleController {
|
|||
}
|
||||
|
||||
fn main() {
|
||||
wasm_bindgen_futures::spawn_local(dioxus_web::WebsysRenderer::start(|ctx| {
|
||||
let title = use_read(&ctx, &TITLE);
|
||||
let subtitle = use_read(&ctx, &SUBTITLE);
|
||||
let controller = TitleController::new(use_recoil_api(&ctx));
|
||||
wasm_bindgen_futures::spawn_local(dioxus_web::WebsysRenderer::start(|cx| {
|
||||
let title = use_read(&cx, &TITLE);
|
||||
let subtitle = use_read(&cx, &SUBTITLE);
|
||||
let controller = TitleController::new(use_recoil_api(&cx));
|
||||
|
||||
rsx! { in ctx,
|
||||
rsx! { in cx,
|
||||
div {
|
||||
"{title}"
|
||||
"{subtitle}"
|
||||
|
|
|
@ -19,11 +19,11 @@ fn update_title(api: &RecoilApi) {
|
|||
}
|
||||
}
|
||||
|
||||
static App: FC<()> = |ctx| {
|
||||
let title = use_read(&ctx, &TITLE);
|
||||
let next_light = use_recoil_api(&ctx, |api| move |_| update_title(&api));
|
||||
static App: FC<()> = |cx| {
|
||||
let title = use_read(&cx, &TITLE);
|
||||
let next_light = use_recoil_api(&cx, |api| move |_| update_title(&api));
|
||||
|
||||
rsx! { in ctx,
|
||||
rsx! { in cx,
|
||||
div {
|
||||
"{title}"
|
||||
button { onclick: {next_light}, "Next light" }
|
||||
|
|
|
@ -31,13 +31,13 @@ const TODOS: EcsModel<u32, TodoModel> = |builder| {};
|
|||
// const SELECT_TITLE: SelectorBorrowed<u32, &str> = |s, k| TODOS.field(0).select(k);
|
||||
// const SELECT_SUBTITLE: SelectorBorrowed<u32, &str> = |s, k| TODOS.field(1).select(k);
|
||||
|
||||
static App: FC<()> = |ctx| {
|
||||
use_init_recoil_root(ctx, |_| {});
|
||||
static App: FC<()> = |cx| {
|
||||
use_init_recoil_root(cx, |_| {});
|
||||
|
||||
// let title = use_recoil_value(ctx, &C_SELECTOR);
|
||||
// let title = use_recoil_value(cx, &C_SELECTOR);
|
||||
|
||||
let title = "";
|
||||
rsx! { in ctx,
|
||||
rsx! { in cx,
|
||||
div {
|
||||
"{title}"
|
||||
// button { onclick: {next_light}, "Next light" }
|
||||
|
|
|
@ -13,18 +13,18 @@ struct Todo {
|
|||
content: String,
|
||||
}
|
||||
|
||||
static App: FC<()> = |ctx| {
|
||||
use_init_recoil_root(ctx, move |cfg| {});
|
||||
static App: FC<()> = |cx| {
|
||||
use_init_recoil_root(cx, move |cfg| {});
|
||||
|
||||
let todos = use_read_family(ctx, &TODOS);
|
||||
let todos = use_read_family(cx, &TODOS);
|
||||
|
||||
// rsx! { in ctx,
|
||||
// rsx! { in cx,
|
||||
// div {
|
||||
// h1 {"Basic Todolist with AtomFamilies in Recoil.rs"}
|
||||
// ul { { todos.keys().map(|id| rsx! { Child { id: *id } }) } }
|
||||
// }
|
||||
// }
|
||||
ctx.render(html! {
|
||||
cx.render(html! {
|
||||
<a href="#" class="">
|
||||
<img class="inline-block h-10 w-10 rounded-full object-cover ring-2 ring-white" src="/images/person/4.jpg" alt="Jade"/>
|
||||
</a>
|
||||
|
@ -36,10 +36,10 @@ struct ChildProps {
|
|||
id: Uuid,
|
||||
}
|
||||
|
||||
static Child: FC<ChildProps> = |ctx| {
|
||||
let (todo, set_todo) = use_read_write(ctx, &TODOS.select(&ctx.id));
|
||||
static Child: FC<ChildProps> = |cx| {
|
||||
let (todo, set_todo) = use_read_write(cx, &TODOS.select(&cx.id));
|
||||
|
||||
rsx! { in ctx,
|
||||
rsx! { in cx,
|
||||
li {
|
||||
h1 {"{todo.title}"}
|
||||
input { type: "checkbox", name: "scales", checked: "{todo.checked}" }
|
||||
|
|
|
@ -12,11 +12,11 @@ struct Todo {
|
|||
contents: String,
|
||||
}
|
||||
|
||||
static App: FC<()> = |ctx| {
|
||||
use_init_recoil_root(ctx, |_| {});
|
||||
let todos = use_read(&ctx, &TODOS);
|
||||
static App: FC<()> = |cx| {
|
||||
use_init_recoil_root(cx, |_| {});
|
||||
let todos = use_read(&cx, &TODOS);
|
||||
|
||||
rsx! { in ctx,
|
||||
rsx! { in cx,
|
||||
div {
|
||||
"Basic Todolist with AtomFamilies in Recoil.rs"
|
||||
}
|
||||
|
@ -28,11 +28,11 @@ struct ChildProps {
|
|||
id: Uuid,
|
||||
}
|
||||
|
||||
static Child: FC<ChildProps> = |ctx| {
|
||||
let todo = use_read(ctx, &TODOS).get(&ctx.id).unwrap();
|
||||
// let (todo, set_todo) = use_read_write(ctx, &TODOS);
|
||||
static Child: FC<ChildProps> = |cx| {
|
||||
let todo = use_read(cx, &TODOS).get(&cx.id).unwrap();
|
||||
// let (todo, set_todo) = use_read_write(cx, &TODOS);
|
||||
|
||||
rsx! { in ctx,
|
||||
rsx! { in cx,
|
||||
div {
|
||||
h1 {"{todo.title}"}
|
||||
input { type: "checkbox", name: "scales", checked: "{todo.checked}" }
|
||||
|
|
|
@ -3,12 +3,12 @@ use recoil::*;
|
|||
|
||||
const COUNT: Atom<i32> = |_| 0;
|
||||
|
||||
static App: FC<()> = |ctx| {
|
||||
use_init_recoil_root(ctx, |_| {});
|
||||
static App: FC<()> = |cx| {
|
||||
use_init_recoil_root(cx, |_| {});
|
||||
|
||||
let (count, set_count) = use_read_write(&ctx, &COUNT);
|
||||
let (count, set_count) = use_read_write(&cx, &COUNT);
|
||||
|
||||
rsx! { in ctx,
|
||||
rsx! { in cx,
|
||||
div {
|
||||
"Count: {count}"
|
||||
br {}
|
||||
|
|
|
@ -17,12 +17,12 @@ const D_SELECTOR: SelectorFamilyBorrowed<i32, i32> = |api, key| -> &i32 {
|
|||
a
|
||||
};
|
||||
|
||||
static App: FC<()> = |ctx| {
|
||||
use_init_recoil_root(ctx, |_| {});
|
||||
static App: FC<()> = |cx| {
|
||||
use_init_recoil_root(cx, |_| {});
|
||||
|
||||
let title = use_read(ctx, &C_SELECTOR);
|
||||
let title = use_read(cx, &C_SELECTOR);
|
||||
|
||||
rsx! { in ctx,
|
||||
rsx! { in cx,
|
||||
div {
|
||||
"{title}"
|
||||
// button { onclick: {next_light}, "Next light" }
|
||||
|
|
|
@ -5,9 +5,9 @@ const A: Atom<i32> = |_| 0;
|
|||
const B: Atom<i32> = |_| 0;
|
||||
const C: Selector<i32> = |api| api.get(&A) + api.get(&B);
|
||||
|
||||
static App: FC<()> = |ctx| {
|
||||
use_init_recoil_root(ctx, |_| {});
|
||||
rsx! { in ctx,
|
||||
static App: FC<()> = |cx| {
|
||||
use_init_recoil_root(cx, |_| {});
|
||||
rsx! { in cx,
|
||||
div {
|
||||
Banner {}
|
||||
BtnA {}
|
||||
|
@ -16,14 +16,14 @@ static App: FC<()> = |ctx| {
|
|||
}
|
||||
};
|
||||
|
||||
static Banner: FC<()> = |ctx| {
|
||||
let count = use_read(&ctx, &C);
|
||||
ctx.render(rsx! { h1 { "Count: {count}" } })
|
||||
static Banner: FC<()> = |cx| {
|
||||
let count = use_read(&cx, &C);
|
||||
cx.render(rsx! { h1 { "Count: {count}" } })
|
||||
};
|
||||
|
||||
static BtnA: FC<()> = |ctx| {
|
||||
let (a, set) = use_read_write(&ctx, &A);
|
||||
rsx! { in ctx,
|
||||
static BtnA: FC<()> = |cx| {
|
||||
let (a, set) = use_read_write(&cx, &A);
|
||||
rsx! { in cx,
|
||||
div { "a"
|
||||
button { "+", onclick: move |_| set(a + 1) }
|
||||
button { "-", onclick: move |_| set(a - 1) }
|
||||
|
@ -31,9 +31,9 @@ static BtnA: FC<()> = |ctx| {
|
|||
}
|
||||
};
|
||||
|
||||
static BtnB: FC<()> = |ctx| {
|
||||
let (b, set) = use_read_write(&ctx, &B);
|
||||
rsx! { in ctx,
|
||||
static BtnB: FC<()> = |cx| {
|
||||
let (b, set) = use_read_write(&cx, &B);
|
||||
rsx! { in cx,
|
||||
div { "b"
|
||||
button { "+", onclick: move |_| set(b + 1) }
|
||||
button { "-", onclick: move |_| set(b - 1) }
|
||||
|
|
|
@ -2,7 +2,7 @@ fn main() {}
|
|||
|
||||
use dioxus_core::prelude::*;
|
||||
|
||||
static App: FC<()> = |ctx| {
|
||||
static App: FC<()> = |cx| {
|
||||
//
|
||||
use_initialize_app()
|
||||
};
|
||||
|
|
|
@ -13,23 +13,23 @@ use std::future::Future;
|
|||
|
||||
use dioxus_core::prelude::*;
|
||||
|
||||
static App: FC<()> = |ctx| {
|
||||
static App: FC<()> = |cx| {
|
||||
//
|
||||
|
||||
let title = use_async_atom();
|
||||
let title_card = suspend(&ctx, title, move |val| {
|
||||
let title_card = suspend(&cx, title, move |val| {
|
||||
//
|
||||
rsx!(in ctx, div {
|
||||
rsx!(in cx, div {
|
||||
h3 { "{val}" }
|
||||
})
|
||||
});
|
||||
|
||||
// let fut = (use_async_atom(), use_async_atom());
|
||||
// let title_card2 = ctx.suspend(fut, move |(text, text2)| {
|
||||
// ctx.render(rsx!( h3 { "{text}" } ))
|
||||
// let title_card2 = cx.suspend(fut, move |(text, text2)| {
|
||||
// cx.render(rsx!( h3 { "{text}" } ))
|
||||
// });
|
||||
|
||||
ctx.render(rsx! {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
{title_card}
|
||||
// {title_card2}
|
||||
|
|
|
@ -64,7 +64,7 @@ Also, we want selectors to have internal dependencies.
|
|||
## Async atoms
|
||||
|
||||
```rust
|
||||
let (atom, set_atom, modify_atom) = (ATOM.use_read(ctx), ATOM.use_write(ctx), ATOM.use_modify(ctx));
|
||||
let (atom, set_atom, modify_atom) = (ATOM.use_read(cx), ATOM.use_write(cx), ATOM.use_modify(cx));
|
||||
|
||||
const Title: AsyncAtom<String> = |builder| {
|
||||
builder.on_set(|api, new_val| async {
|
||||
|
@ -93,10 +93,10 @@ const ContentCards: SelectorFamily<Uuid, ContentCard> = |api, key| api.on_get_as
|
|||
data
|
||||
})
|
||||
|
||||
static ContentCard: FC<()> = |ctx| {
|
||||
let body = async match use_recoil_value()(ctx.id).await {
|
||||
Ok(content) => rsx!{in ctx, p {"{content}"} }
|
||||
Err(e) => rsx!{in ctx, p {"Failed to load"}}
|
||||
static ContentCard: FC<()> = |cx| {
|
||||
let body = async match use_recoil_value()(cx.id).await {
|
||||
Ok(content) => rsx!{in cx, p {"{content}"} }
|
||||
Err(e) => rsx!{in cx, p {"Failed to load"}}
|
||||
};
|
||||
|
||||
rsx!{
|
||||
|
|
|
@ -31,15 +31,15 @@ mod traits {
|
|||
|
||||
// Atoms, selectors, and their family variants are readable
|
||||
pub trait Readable<T: AtomValue>: Sized + Copy {
|
||||
fn use_read<'a, P: 'static>(self, ctx: Context<'a, P>) -> &'a T {
|
||||
hooks::use_read(&ctx, self)
|
||||
fn use_read<'a, P: 'static>(self, cx: Context<'a, P>) -> &'a T {
|
||||
hooks::use_read(&cx, self)
|
||||
}
|
||||
|
||||
// This returns a future of the value
|
||||
// If the atom is currently pending, that future will resolve to pending
|
||||
// If the atom is currently ready, the future will immediately resolve
|
||||
// if the atom switches from ready to pending, the component will re-run, returning a pending future
|
||||
fn use_read_async<'a, P>(self, ctx: Context<'a, P>) -> &'a T {
|
||||
fn use_read_async<'a, P>(self, cx: Context<'a, P>) -> &'a T {
|
||||
todo!()
|
||||
}
|
||||
|
||||
|
@ -53,11 +53,11 @@ mod traits {
|
|||
// Only atoms and atom families are writable
|
||||
// Selectors and selector families are not
|
||||
pub trait Writable<T: AtomValue>: Readable<T> + Sized {
|
||||
fn use_read_write<'a, P>(self, ctx: Context<'a, P>) -> (&'a T, &'a Rc<dyn Fn(T)>) {
|
||||
fn use_read_write<'a, P>(self, cx: Context<'a, P>) -> (&'a T, &'a Rc<dyn Fn(T)>) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn use_write<'a, P>(self, ctx: Context<'a, P>) -> &'a Rc<dyn Fn(T)> {
|
||||
fn use_write<'a, P>(self, cx: Context<'a, P>) -> &'a Rc<dyn Fn(T)> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
@ -91,13 +91,13 @@ mod atoms {
|
|||
use super::*;
|
||||
use dioxus_core::prelude::Context;
|
||||
|
||||
fn _test(ctx: Context<()>) {
|
||||
fn _test(cx: Context<()>) {
|
||||
const EXAMPLE_ATOM: Atom<i32> = |_| 10;
|
||||
|
||||
// ensure that atoms are both read and write
|
||||
let _ = use_read(&ctx, &EXAMPLE_ATOM);
|
||||
let _ = use_read_write(&ctx, &EXAMPLE_ATOM);
|
||||
let _ = use_write(&ctx, &EXAMPLE_ATOM);
|
||||
let _ = use_read(&cx, &EXAMPLE_ATOM);
|
||||
let _ = use_read_write(&cx, &EXAMPLE_ATOM);
|
||||
let _ = use_write(&cx, &EXAMPLE_ATOM);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -159,9 +159,9 @@ mod atomfamily {
|
|||
use super::*;
|
||||
const Titles: AtomHashMap<u32, &str> = |map| {};
|
||||
|
||||
fn test(ctx: Context<()>) {
|
||||
let title = Titles.select(&10).use_read(ctx);
|
||||
let t2 = use_read(&ctx, &Titles.select(&10));
|
||||
fn test(cx: Context<()>) {
|
||||
let title = Titles.select(&10).use_read(cx);
|
||||
let t2 = use_read(&cx, &Titles.select(&10));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -370,8 +370,8 @@ mod hooks {
|
|||
use super::*;
|
||||
use dioxus_core::{hooks::use_ref, prelude::Context, virtual_dom::Scoped};
|
||||
|
||||
pub fn use_init_recoil_root<P>(ctx: Context<P>, cfg: impl Fn(())) {
|
||||
ctx.use_create_context(move || RefCell::new(RecoilRoot::new()))
|
||||
pub fn use_init_recoil_root<P>(cx: Context<P>, cfg: impl Fn(())) {
|
||||
cx.use_create_context(move || RefCell::new(RecoilRoot::new()))
|
||||
}
|
||||
|
||||
/// Gain access to the recoil API directly - set, get, modify, everything
|
||||
|
@ -381,17 +381,17 @@ mod hooks {
|
|||
///
|
||||
/// You can use this method to create controllers that perform much more complex actions than set/get
|
||||
/// However, be aware that "getting" values through this hook will not subscribe the component to any updates.
|
||||
pub fn use_recoil_api<'a>(ctx: &impl Scoped<'a>) -> &'a Rc<RecoilContext> {
|
||||
ctx.use_context::<RecoilContext>()
|
||||
pub fn use_recoil_api<'a>(cx: &impl Scoped<'a>) -> &'a Rc<RecoilContext> {
|
||||
cx.use_context::<RecoilContext>()
|
||||
}
|
||||
|
||||
pub fn use_write<'a, T: AtomValue>(
|
||||
ctx: &impl Scoped<'a>,
|
||||
cx: &impl Scoped<'a>,
|
||||
// todo: this shouldn't need to be static
|
||||
writable: impl Writable<T>,
|
||||
) -> &'a Rc<dyn Fn(T)> {
|
||||
let api = use_recoil_api(ctx);
|
||||
ctx.use_hook(
|
||||
let api = use_recoil_api(cx);
|
||||
cx.use_hook(
|
||||
move || {
|
||||
let api = api.clone();
|
||||
let raw_id = writable.static_id();
|
||||
|
@ -413,7 +413,7 @@ mod hooks {
|
|||
/// This is useful if you need the memoized Atom value. However, Rc<T> is not as easy to
|
||||
/// work with as
|
||||
pub fn use_read_raw<'a, T: AtomValue>(
|
||||
ctx: &impl Scoped<'a>,
|
||||
cx: &impl Scoped<'a>,
|
||||
readable: impl Readable<T>,
|
||||
) -> &'a Rc<T> {
|
||||
struct ReadHook<T> {
|
||||
|
@ -421,12 +421,12 @@ mod hooks {
|
|||
consumer_id: u32,
|
||||
}
|
||||
|
||||
let api = use_recoil_api(ctx);
|
||||
ctx.use_hook(
|
||||
let api = use_recoil_api(cx);
|
||||
cx.use_hook(
|
||||
move || {
|
||||
let mut api = api.as_ref().borrow_mut();
|
||||
|
||||
let update = ctx.schedule_update();
|
||||
let update = cx.schedule_update();
|
||||
let val = api.try_get_raw(readable).unwrap();
|
||||
let id = api.subscribe(readable, update);
|
||||
ReadHook {
|
||||
|
@ -449,8 +449,8 @@ mod hooks {
|
|||
}
|
||||
|
||||
///
|
||||
pub fn use_read<'a, T: AtomValue>(ctx: &impl Scoped<'a>, readable: impl Readable<T>) -> &'a T {
|
||||
use_read_raw(ctx, readable).as_ref()
|
||||
pub fn use_read<'a, T: AtomValue>(cx: &impl Scoped<'a>, readable: impl Readable<T>) -> &'a T {
|
||||
use_read_raw(cx, readable).as_ref()
|
||||
}
|
||||
|
||||
/// # Use an atom in both read and write
|
||||
|
@ -463,16 +463,16 @@ mod hooks {
|
|||
///
|
||||
/// ```
|
||||
/// const Title: Atom<&str> = |_| "hello";
|
||||
/// let (title, set_title) = use_read_write(ctx, &Title);
|
||||
/// let (title, set_title) = use_read_write(cx, &Title);
|
||||
///
|
||||
/// // equivalent to:
|
||||
/// let (title, set_title) = (use_read(ctx, &Title), use_write(ctx, &Title));
|
||||
/// let (title, set_title) = (use_read(cx, &Title), use_write(cx, &Title));
|
||||
/// ```
|
||||
pub fn use_read_write<'a, T: AtomValue + 'static>(
|
||||
ctx: &impl Scoped<'a>,
|
||||
cx: &impl Scoped<'a>,
|
||||
writable: impl Writable<T>,
|
||||
) -> (&'a T, &'a Rc<dyn Fn(T)>) {
|
||||
(use_read(ctx, writable), use_write(ctx, writable))
|
||||
(use_read(cx, writable), use_write(cx, writable))
|
||||
}
|
||||
|
||||
/// # Modify an atom without using `use_read`.
|
||||
|
@ -491,12 +491,12 @@ mod hooks {
|
|||
/// ## Example
|
||||
///
|
||||
/// ```ignore
|
||||
/// let modify_atom = use_modify(ctx, Atom);
|
||||
/// let modify_atom = use_modify(cx, Atom);
|
||||
///
|
||||
/// modify_atom(&|a| *a += 1)
|
||||
/// ```
|
||||
pub fn use_modify<'a, T: AtomValue + 'static + Clone, P>(
|
||||
ctx: Context<'a, P>,
|
||||
cx: Context<'a, P>,
|
||||
writable: impl Writable<T>,
|
||||
) -> impl Fn(&dyn Fn()) {
|
||||
|_| {}
|
||||
|
@ -506,7 +506,7 @@ mod hooks {
|
|||
/// !! Any changes to the family will cause this subscriber to update
|
||||
/// Try not to put this at the very top-level of your app.
|
||||
pub fn use_read_family<'a, K, V, P>(
|
||||
ctx: Context<'a, P>,
|
||||
cx: Context<'a, P>,
|
||||
t: &AtomHashMap<K, V>,
|
||||
) -> &'a im_rc::HashMap<K, V> {
|
||||
todo!()
|
||||
|
@ -532,9 +532,9 @@ mod utils {
|
|||
pub fn RecoilApp<T: 'static>(
|
||||
root: impl for<'a> Fn(Context<'a, T>) -> VNode,
|
||||
) -> impl for<'a> Fn(Context<'a, T>) -> VNode {
|
||||
move |ctx| {
|
||||
use_init_recoil_root(ctx, |_| {});
|
||||
root(ctx)
|
||||
move |cx| {
|
||||
use_init_recoil_root(cx, |_| {});
|
||||
root(cx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -133,7 +133,7 @@ impl ToTokens for FunctionComponent {
|
|||
}
|
||||
|
||||
impl<'a> FC for #function_name<'a> {
|
||||
fn render(ctx: Context<'_>, props: &#function_name<'a>) -> VNode {
|
||||
fn render(cx: Context<'_>, props: &#function_name<'a>) -> VNode {
|
||||
let #function_name {
|
||||
..
|
||||
} = props;
|
||||
|
@ -150,12 +150,12 @@ impl ToTokens for FunctionComponent {
|
|||
// name: &'a str
|
||||
// }
|
||||
|
||||
// pub fn component<'a>(ctx: &'a Context<'a, Props>) -> VNode<'a> {
|
||||
// pub fn component<'a>(cx: &'a Context<'a, Props>) -> VNode<'a> {
|
||||
// // Destructure the props into the parent scope
|
||||
// // todo: handle expansion of lifetimes
|
||||
// let Props {
|
||||
// name
|
||||
// } = ctx.props;
|
||||
// } = cx.props;
|
||||
|
||||
// #block
|
||||
// }
|
||||
|
|
|
@ -39,7 +39,7 @@ impl Parse for HtmlRender {
|
|||
return input.parse::<LitStr>()?.parse::<HtmlRender>();
|
||||
}
|
||||
|
||||
// let ctx: Ident = s.parse()?;
|
||||
// let cx: Ident = s.parse()?;
|
||||
// s.parse::<Token![,]>()?;
|
||||
// if elements are in an array, return a bumpalo::collections::Vec rather than a Node.
|
||||
let kind = if input.peek(token::Bracket) {
|
||||
|
@ -64,8 +64,8 @@ impl ToTokens for HtmlRender {
|
|||
|
||||
// create a lazy tree that accepts a bump allocator
|
||||
let final_tokens = quote! {
|
||||
dioxus::prelude::LazyNodes::new(move |ctx| {
|
||||
let bump = &ctx.bump();
|
||||
dioxus::prelude::LazyNodes::new(move |cx| {
|
||||
let bump = &cx.bump();
|
||||
|
||||
#new_toks
|
||||
})
|
||||
|
@ -152,10 +152,10 @@ struct Element {
|
|||
|
||||
impl ToTokens for ToToksCtx<&Element> {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream2) {
|
||||
// let ctx = self.ctx;
|
||||
// let cx = self.cx;
|
||||
let name = &self.inner.name.to_string();
|
||||
tokens.append_all(quote! {
|
||||
dioxus::builder::ElementBuilder::new(ctx, #name)
|
||||
dioxus::builder::ElementBuilder::new(cx, #name)
|
||||
});
|
||||
for attr in self.inner.attrs.iter() {
|
||||
self.recurse(attr).to_tokens(tokens);
|
||||
|
|
|
@ -61,8 +61,8 @@ pub fn html_template(s: TokenStream) -> TokenStream {
|
|||
/// ```ignore
|
||||
///
|
||||
/// #[fc]
|
||||
/// fn Example(ctx: Context, name: &str) -> VNode {
|
||||
/// ctx.render(rsx! { h1 {"hello {name}"} })
|
||||
/// fn Example(cx: Context, name: &str) -> VNode {
|
||||
/// cx.render(rsx! { h1 {"hello {name}"} })
|
||||
/// }
|
||||
/// ```
|
||||
#[proc_macro_attribute]
|
||||
|
|
|
@ -120,14 +120,14 @@ impl ToTokens for Component {
|
|||
|
||||
let childs = &self.children;
|
||||
let children = quote! {
|
||||
ChildrenList::new(__ctx)
|
||||
ChildrenList::new(__cx)
|
||||
#( .add_child(#childs) )*
|
||||
.finish()
|
||||
};
|
||||
|
||||
tokens.append_all(quote! {
|
||||
dioxus::builder::virtual_child(
|
||||
__ctx,
|
||||
__cx,
|
||||
#name,
|
||||
#builder,
|
||||
#key_token,
|
||||
|
|
|
@ -68,7 +68,7 @@ impl ToTokens for Element {
|
|||
let name = &self.name.to_string();
|
||||
|
||||
tokens.append_all(quote! {
|
||||
dioxus::builder::ElementBuilder::new(__ctx, #name)
|
||||
dioxus::builder::ElementBuilder::new(__cx, #name)
|
||||
});
|
||||
|
||||
for attr in self.attrs.iter() {
|
||||
|
@ -221,13 +221,13 @@ impl ToTokens for ElementAttr {
|
|||
}
|
||||
AttrType::Event(event) => {
|
||||
tokens.append_all(quote! {
|
||||
.add_listener(dioxus::events::on::#nameident(__ctx, #event))
|
||||
.add_listener(dioxus::events::on::#nameident(__cx, #event))
|
||||
});
|
||||
}
|
||||
AttrType::EventTokens(event) => {
|
||||
//
|
||||
tokens.append_all(quote! {
|
||||
.add_listener(dioxus::events::on::#nameident(__ctx, #event))
|
||||
.add_listener(dioxus::events::on::#nameident(__cx, #event))
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,14 +50,14 @@ impl ToTokens for Fragment {
|
|||
fn to_tokens(&self, tokens: &mut TokenStream2) {
|
||||
let childs = &self.children;
|
||||
let children = quote! {
|
||||
ChildrenList::new(__ctx)
|
||||
ChildrenList::new(__cx)
|
||||
#( .add_child(#childs) )*
|
||||
.finish()
|
||||
};
|
||||
tokens.append_all(quote! {
|
||||
// #key_token,
|
||||
dioxus::builder::vfragment(
|
||||
__ctx,
|
||||
__cx,
|
||||
None,
|
||||
#children
|
||||
)
|
||||
|
|
|
@ -81,14 +81,14 @@ impl ToTokens for RsxRender {
|
|||
} else {
|
||||
let childs = &self.roots;
|
||||
let children = quote! {
|
||||
ChildrenList::new(__ctx)
|
||||
ChildrenList::new(__cx)
|
||||
#( .add_child(#childs) )*
|
||||
.finish()
|
||||
};
|
||||
quote! {
|
||||
// #key_token,
|
||||
dioxus::builder::vfragment(
|
||||
__ctx,
|
||||
__cx,
|
||||
None,
|
||||
#children
|
||||
)
|
||||
|
@ -96,17 +96,17 @@ impl ToTokens for RsxRender {
|
|||
};
|
||||
|
||||
match &self.custom_context {
|
||||
// The `in ctx` pattern allows directly rendering
|
||||
// The `in cx` pattern allows directly rendering
|
||||
Some(ident) => out_tokens.append_all(quote! {
|
||||
#ident.render(dioxus::prelude::LazyNodes::new(move |__ctx|{
|
||||
let bump = &__ctx.bump();
|
||||
#ident.render(dioxus::prelude::LazyNodes::new(move |__cx|{
|
||||
let bump = &__cx.bump();
|
||||
#inner
|
||||
}))
|
||||
}),
|
||||
// Otherwise we just build the LazyNode wrapper
|
||||
None => out_tokens.append_all(quote! {
|
||||
dioxus::prelude::LazyNodes::new(move |__ctx|{
|
||||
let bump = &__ctx.bump();
|
||||
dioxus::prelude::LazyNodes::new(move |__cx|{
|
||||
let bump = &__cx.bump();
|
||||
#inner
|
||||
})
|
||||
}),
|
||||
|
|
|
@ -46,7 +46,7 @@ impl Parse for RsxTemplate {
|
|||
|
||||
// let new_stream = TokenStream::from(t.to_s)
|
||||
|
||||
// let ctx: Ident = s.parse()?;
|
||||
// let cx: Ident = s.parse()?;
|
||||
// s.parse::<Token![,]>()?;
|
||||
// if elements are in an array, return a bumpalo::collections::Vec rather than a Node.
|
||||
// let kind = if s.peek(token::Bracket) {
|
||||
|
@ -72,8 +72,8 @@ impl ToTokens for RsxTemplate {
|
|||
|
||||
// // create a lazy tree that accepts a bump allocator
|
||||
// let final_tokens = quote! {
|
||||
// dioxus::prelude::LazyNodes::new(move |ctx| {
|
||||
// let bump = &ctx.bump();
|
||||
// dioxus::prelude::LazyNodes::new(move |cx| {
|
||||
// let bump = &cx.bump();
|
||||
|
||||
// #new_toks
|
||||
// })
|
||||
|
|
|
@ -40,6 +40,9 @@ serde = { version="1", features=["derive"], optional=true }
|
|||
smallvec = "1.6.1"
|
||||
|
||||
|
||||
futures = "0.3.15"
|
||||
|
||||
|
||||
[features]
|
||||
default = []
|
||||
serialize = ["serde", "generational-arena/serde"]
|
||||
|
|
|
@ -2,10 +2,10 @@ fn main() {}
|
|||
|
||||
use dioxus_core::prelude::*;
|
||||
|
||||
static Example: FC<()> = |ctx| {
|
||||
ctx.render(dioxus_core::prelude::LazyNodes::new(move |ctx| {
|
||||
let bump = ctx.bump();
|
||||
dioxus_core::builder::ElementBuilder::new(ctx, "h1")
|
||||
static Example: FC<()> = |cx| {
|
||||
cx.render(dioxus_core::prelude::LazyNodes::new(move |cx| {
|
||||
let bump = cx.bump();
|
||||
dioxus_core::builder::ElementBuilder::new(cx, "h1")
|
||||
.children([dioxus_core::builder::text3(bump, format_args!("hello"))])
|
||||
.finish()
|
||||
}))
|
||||
|
@ -14,13 +14,13 @@ static Example: FC<()> = |ctx| {
|
|||
struct Props {
|
||||
text: String,
|
||||
}
|
||||
static Example2: FC<Props> = |ctx| {
|
||||
ctx.render(dioxus_core::prelude::LazyNodes::new(move |__ctx| {
|
||||
let bump = __ctx.bump();
|
||||
dioxus_core::builder::ElementBuilder::new(__ctx, "h1")
|
||||
static Example2: FC<Props> = |cx| {
|
||||
cx.render(dioxus_core::prelude::LazyNodes::new(move |__cx| {
|
||||
let bump = __cx.bump();
|
||||
dioxus_core::builder::ElementBuilder::new(__cx, "h1")
|
||||
.children([dioxus_core::builder::text3(
|
||||
bump,
|
||||
format_args!("{}", ctx.props.text),
|
||||
format_args!("{}", cx.props.text),
|
||||
)])
|
||||
.finish()
|
||||
}))
|
||||
|
|
|
@ -19,15 +19,15 @@ struct ListItem {
|
|||
age: u32,
|
||||
}
|
||||
|
||||
fn app(ctx: Context<AppProps>) -> VNode {
|
||||
let (val, set_val) = use_state(&ctx, || 0);
|
||||
fn app(cx: Context<AppProps>) -> VNode {
|
||||
let (val, set_val) = use_state(&cx, || 0);
|
||||
|
||||
ctx.render(LazyNodes::new(move |_nodectx| {
|
||||
builder::ElementBuilder::new(_nodectx, "div")
|
||||
cx.render(LazyNodes::new(move |_nodecx| {
|
||||
builder::ElementBuilder::new(_nodecx, "div")
|
||||
.iter_child({
|
||||
ctx.items.iter().map(|child| {
|
||||
cx.items.iter().map(|child| {
|
||||
builder::virtual_child(
|
||||
_nodectx,
|
||||
_nodecx,
|
||||
ChildItem,
|
||||
ChildProps {
|
||||
item: child.clone(),
|
||||
|
@ -38,8 +38,8 @@ fn app(ctx: Context<AppProps>) -> VNode {
|
|||
)
|
||||
})
|
||||
})
|
||||
.iter_child([builder::ElementBuilder::new(_nodectx, "div")
|
||||
.iter_child([builder::text3(_nodectx.bump(), format_args!("{}", val))])
|
||||
.iter_child([builder::ElementBuilder::new(_nodecx, "div")
|
||||
.iter_child([builder::text3(_nodecx.bump(), format_args!("{}", val))])
|
||||
.finish()])
|
||||
.finish()
|
||||
}))
|
||||
|
|
|
@ -13,21 +13,21 @@ struct Props {
|
|||
static Example: FC<Props> = |cpt| {
|
||||
todo!()
|
||||
|
||||
// let value = ctx.use_context(|c: &SomeContext| c.items.last().unwrap());
|
||||
// let value = cx.use_context(|c: &SomeContext| c.items.last().unwrap());
|
||||
|
||||
// ctx.render(LazyNodes::new(move |bump| {
|
||||
// cx.render(LazyNodes::new(move |bump| {
|
||||
// builder::ElementBuilder::new(bump, "button")
|
||||
// .on("click", move |_| {
|
||||
// println!("Value is {}", ctx.name);
|
||||
// println!("Value is {}", cx.name);
|
||||
// println!("Value is {}", value.as_str());
|
||||
// println!("Value is {}", *value);
|
||||
// })
|
||||
// .on("click", move |_| {
|
||||
// println!("Value is {}", ctx.name);
|
||||
// println!("Value is {}", cx.name);
|
||||
// })
|
||||
// .finish()
|
||||
// }))
|
||||
// ctx.render(html! {
|
||||
// cx.render(html! {
|
||||
// <div>
|
||||
// <button onclick={move |_| println!("Value is {}", value)} />
|
||||
// <button onclick={move |_| println!("Value is {}", value)} />
|
||||
|
|
|
@ -34,7 +34,7 @@ fn main() {}
|
|||
// 2: Trees are not evaluated
|
||||
|
||||
// */
|
||||
// let example_caller = move |ctx: &Bump| {
|
||||
// let example_caller = move |cx: &Bump| {
|
||||
// todo!()
|
||||
// // let p = Props { blah: true, text };
|
||||
// // let c = Context { props: &p };
|
||||
|
@ -57,11 +57,11 @@ fn main() {}
|
|||
// }
|
||||
// }
|
||||
|
||||
// fn component<'a>(ctx: Context<'a, Props>) -> VNode<'a> {
|
||||
// fn component<'a>(cx: Context<'a, Props>) -> VNode<'a> {
|
||||
// // Write asynchronous rendering code that immediately returns a "suspended" VNode
|
||||
// // The concurrent API will then progress this component when the future finishes
|
||||
// // You can suspend the entire component, or just parts of it
|
||||
// let product_list = ctx.suspend(async {
|
||||
// let product_list = cx.suspend(async {
|
||||
// // Suspend the rendering that completes when the future is done
|
||||
// match fetch_data().await {
|
||||
// Ok(data) => html! { <div> "success!" </div>},
|
||||
|
@ -70,7 +70,7 @@ fn main() {}
|
|||
// });
|
||||
|
||||
// // todo!()
|
||||
// ctx.render(html! {
|
||||
// cx.render(html! {
|
||||
// <div>
|
||||
// <h1> "Products" </h1>
|
||||
// <button> "hello!" </button>
|
||||
|
@ -82,27 +82,27 @@ fn main() {}
|
|||
// })
|
||||
// }
|
||||
|
||||
// fn BuilderComp<'a>(ctx: Context<'a, Props>) -> VNode<'a> {
|
||||
// fn BuilderComp<'a>(cx: Context<'a, Props>) -> VNode<'a> {
|
||||
// // VNodes can be constructed via a builder or the html! macro
|
||||
// // However, both of these are "lazy" - they need to be evaluated (aka, "viewed")
|
||||
// // We can "view" them with Context for ultimate speed while inside components
|
||||
// ctx.render(|bump| {
|
||||
// cx.render(|bump| {
|
||||
// div(bump)
|
||||
// .attr("class", "edit")
|
||||
// .child(text("Hello"))
|
||||
// .child(text(ctx.ctx.text.as_ref()))
|
||||
// .child(text(cx.cx.text.as_ref()))
|
||||
// .finish()
|
||||
// })
|
||||
// }
|
||||
|
||||
// #[fc]
|
||||
// fn EffcComp(ctx: Context, name: &str) -> VNode {
|
||||
// fn EffcComp(cx: Context, name: &str) -> VNode {
|
||||
// // VNodes can be constructed via a builder or the html! macro
|
||||
// // However, both of these are "lazy" - they need to be evaluated (aka, "viewed")
|
||||
// // We can "view" them with Context for ultimate speed while inside components
|
||||
// // use "phase" style allocation;
|
||||
|
||||
// ctx.render(html! {
|
||||
// cx.render(html! {
|
||||
// <div>
|
||||
// // your template goes here
|
||||
// // feel free to directly use "name"
|
||||
|
@ -110,8 +110,8 @@ fn main() {}
|
|||
// })
|
||||
// }
|
||||
|
||||
// fn FullySuspended<'a>(ctx: &'a Context<Props>) -> VNode<'a> {
|
||||
// ctx.suspend(async {
|
||||
// fn FullySuspended<'a>(cx: &'a Context<Props>) -> VNode<'a> {
|
||||
// cx.suspend(async {
|
||||
// let i: i32 = 0;
|
||||
|
||||
// // full suspended works great with just returning VNodes!
|
||||
|
@ -123,7 +123,7 @@ fn main() {}
|
|||
// _ => html! { <div> </div> },
|
||||
// };
|
||||
|
||||
// if ctx.ctx.blah {
|
||||
// if cx.cx.blah {
|
||||
// html! { <div> </div> }
|
||||
// } else {
|
||||
// tex
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
//!
|
||||
//! Note - using the builder pattern does not required the Properties trait to be implemented - the only thing that matters is
|
||||
//! if the type suppports PartialEq. The Properties trait is used by the rsx! and html! macros to generate the type-safe builder
|
||||
//! that ensures compile-time required and optional fields on ctx.
|
||||
//! that ensures compile-time required and optional fields on cx.
|
||||
|
||||
use crate::innerlude::FC;
|
||||
|
||||
|
@ -50,9 +50,9 @@ pub fn fc_to_builder<T: Properties>(_: FC<T>) -> T::Builder {
|
|||
/// Fragments are incredibly useful when necessary, but *do* add cost in the diffing phase.
|
||||
/// Try to avoid nesting fragments if you can. Infinitely nested Fragments *will* cause diffing to crash.
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const Fragment: FC<()> = |ctx| {
|
||||
pub const Fragment: FC<()> = |cx| {
|
||||
use crate::prelude::*;
|
||||
ctx.render(LazyNodes::new(move |c| {
|
||||
crate::nodebuilder::vfragment(c, None, ctx.children())
|
||||
cx.render(LazyNodes::new(move |c| {
|
||||
crate::nodebuilder::vfragment(c, None, cx.children())
|
||||
}))
|
||||
};
|
||||
|
|
|
@ -86,7 +86,7 @@ impl DebugVNodeSource {
|
|||
}
|
||||
|
||||
fn render_nodes(&self) -> VNode {
|
||||
// let ctx = NodeCtx
|
||||
// let cx = NodeCtx
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
@ -97,9 +97,9 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn ensure_creation() -> Result<(), ()> {
|
||||
// static Example: FC<()> = |ctx| {
|
||||
// static Example: FC<()> = |cx| {
|
||||
// //
|
||||
// ctx.render(html! { <div> "hello world" </div> })
|
||||
// cx.render(html! { <div> "hello world" </div> })
|
||||
// };
|
||||
|
||||
// let mut dom = VirtualDom::new(Example);
|
||||
|
|
|
@ -44,6 +44,9 @@ pub enum VirtualEvent {
|
|||
MouseEvent(Rc<dyn on::MouseEvent>),
|
||||
PointerEvent(Rc<dyn on::PointerEvent>),
|
||||
|
||||
// Whenever a task is ready (complete) Dioxus produces this "FiberEvent"
|
||||
FiberEvent { task_id: u16 },
|
||||
|
||||
// image event has conflicting method types
|
||||
// ImageEvent(event_data::ImageEvent),
|
||||
OtherEvent,
|
||||
|
|
|
@ -28,8 +28,8 @@ mod use_state_def {
|
|||
///
|
||||
/// Usage:
|
||||
/// ```ignore
|
||||
/// static Example: FC<()> = |ctx| {
|
||||
/// let (counter, set_counter) = use_state(&ctx, || 0);
|
||||
/// static Example: FC<()> = |cx| {
|
||||
/// let (counter, set_counter) = use_state(&cx, || 0);
|
||||
/// let increment = |_| set_couter(counter + 1);
|
||||
/// let decrement = |_| set_couter(counter + 1);
|
||||
///
|
||||
|
@ -43,7 +43,7 @@ mod use_state_def {
|
|||
/// }
|
||||
/// ```
|
||||
pub fn use_state<'a, 'c, T: 'static, F: FnOnce() -> T>(
|
||||
ctx: &impl Scoped<'a>,
|
||||
cx: &impl Scoped<'a>,
|
||||
initial_state_fn: F,
|
||||
) -> (&'a T, &'a Rc<dyn Fn(T)>) {
|
||||
struct UseState<T: 'static> {
|
||||
|
@ -52,7 +52,7 @@ mod use_state_def {
|
|||
caller: Rc<dyn Fn(T) + 'static>,
|
||||
}
|
||||
|
||||
ctx.use_hook(
|
||||
cx.use_hook(
|
||||
move || UseState {
|
||||
new_val: Rc::new(RefCell::new(None)),
|
||||
current_val: initial_state_fn(),
|
||||
|
@ -61,7 +61,7 @@ mod use_state_def {
|
|||
move |hook| {
|
||||
log::debug!("Use_state set called");
|
||||
let inner = hook.new_val.clone();
|
||||
let scheduled_update = ctx.schedule_update();
|
||||
let scheduled_update = cx.schedule_update();
|
||||
|
||||
// get ownership of the new val and replace the current with the new
|
||||
// -> as_ref -> borrow_mut -> deref_mut -> take
|
||||
|
@ -155,8 +155,8 @@ mod new_use_state_def {
|
|||
///
|
||||
/// Usage:
|
||||
/// ```ignore
|
||||
/// static Example: FC<()> = |ctx| {
|
||||
/// let (counter, set_counter) = use_state(&ctx, || 0);
|
||||
/// static Example: FC<()> = |cx| {
|
||||
/// let (counter, set_counter) = use_state(&cx, || 0);
|
||||
/// let increment = |_| set_couter(counter + 1);
|
||||
/// let decrement = |_| set_couter(counter + 1);
|
||||
///
|
||||
|
@ -170,10 +170,10 @@ mod new_use_state_def {
|
|||
/// }
|
||||
/// ```
|
||||
pub fn use_state_new<'a, 'c, T: 'static, F: FnOnce() -> T>(
|
||||
ctx: &impl Scoped<'a>,
|
||||
cx: &impl Scoped<'a>,
|
||||
initial_state_fn: F,
|
||||
) -> &'a UseState<T> {
|
||||
ctx.use_hook(
|
||||
cx.use_hook(
|
||||
move || UseState {
|
||||
modifier: Rc::new(RefCell::new(None)),
|
||||
current_val: initial_state_fn(),
|
||||
|
@ -182,7 +182,7 @@ mod new_use_state_def {
|
|||
},
|
||||
move |hook| {
|
||||
log::debug!("addr of hook: {:#?}", hook as *const _);
|
||||
let scheduled_update = ctx.schedule_update();
|
||||
let scheduled_update = cx.schedule_update();
|
||||
|
||||
// log::debug!("Checking if new value {:#?}", &hook.current_val);
|
||||
// get ownership of the new val and replace the current with the new
|
||||
|
@ -247,10 +247,10 @@ mod use_ref_def {
|
|||
/// Modifications to this value do not cause updates to the component
|
||||
/// Attach to inner context reference, so context can be consumed
|
||||
pub fn use_ref<'a, T: 'static>(
|
||||
ctx: &impl Scoped<'a>,
|
||||
cx: &impl Scoped<'a>,
|
||||
initial_state_fn: impl FnOnce() -> T + 'static,
|
||||
) -> &'a RefCell<T> {
|
||||
ctx.use_hook(|| RefCell::new(initial_state_fn()), |state| &*state, |_| {})
|
||||
cx.use_hook(|| RefCell::new(initial_state_fn()), |state| &*state, |_| {})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -271,11 +271,11 @@ mod use_reducer_def {
|
|||
/// This is behaves almost exactly the same way as React's "use_state".
|
||||
///
|
||||
pub fn use_reducer<'a, 'c, State: 'static, Action: 'static>(
|
||||
ctx: &impl Scoped<'a>,
|
||||
cx: &impl Scoped<'a>,
|
||||
initial_state_fn: impl FnOnce() -> State,
|
||||
_reducer: impl Fn(&mut State, Action),
|
||||
) -> (&'a State, &'a Box<dyn Fn(Action)>) {
|
||||
ctx.use_hook(
|
||||
cx.use_hook(
|
||||
move || UseReducer {
|
||||
new_val: Rc::new(RefCell::new(None)),
|
||||
current_val: initial_state_fn(),
|
||||
|
@ -283,7 +283,7 @@ mod use_reducer_def {
|
|||
},
|
||||
move |hook| {
|
||||
let _inner = hook.new_val.clone();
|
||||
let scheduled_update = ctx.schedule_update();
|
||||
let scheduled_update = cx.schedule_update();
|
||||
|
||||
// get ownership of the new val and replace the current with the new
|
||||
// -> as_ref -> borrow_mut -> deref_mut -> take
|
||||
|
@ -320,9 +320,9 @@ mod use_reducer_def {
|
|||
}
|
||||
|
||||
// #[allow(unused)]
|
||||
// static Example: FC<()> = |ctx| {
|
||||
// static Example: FC<()> = |cx| {
|
||||
// let (count, reduce) = use_reducer(
|
||||
// &ctx,
|
||||
// &cx,
|
||||
// || 0,
|
||||
// |count, action| match action {
|
||||
// Actions::Incr => *count += 1,
|
||||
|
@ -330,7 +330,7 @@ mod use_reducer_def {
|
|||
// },
|
||||
// );
|
||||
|
||||
// ctx.render(rsx! {
|
||||
// cx.render(rsx! {
|
||||
// div {
|
||||
// h1 {"Count: {count}"}
|
||||
// button {
|
||||
|
@ -347,8 +347,8 @@ mod use_reducer_def {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn use_is_initialized<P>(ctx: Context<P>) -> bool {
|
||||
let val = use_ref(&ctx, || false);
|
||||
pub fn use_is_initialized<P>(cx: Context<P>) -> bool {
|
||||
let val = use_ref(&cx, || false);
|
||||
match *val.borrow() {
|
||||
true => true,
|
||||
false => {
|
||||
|
|
|
@ -29,13 +29,14 @@ where
|
|||
Attributes: 'a + AsRef<[Attribute<'a>]>,
|
||||
Children: 'a + AsRef<[VNode<'a>]>,
|
||||
{
|
||||
ctx: &'b NodeCtx<'a>,
|
||||
cx: &'b NodeCtx<'a>,
|
||||
key: NodeKey<'a>,
|
||||
tag_name: &'a str,
|
||||
tag_name: &'static str,
|
||||
// tag_name: &'a str,
|
||||
listeners: Listeners,
|
||||
attributes: Attributes,
|
||||
children: Children,
|
||||
namespace: Option<&'a str>,
|
||||
namespace: Option<&'static str>,
|
||||
}
|
||||
|
||||
impl<'a, 'b>
|
||||
|
@ -70,10 +71,10 @@ impl<'a, 'b>
|
|||
/// let my_element_builder = ElementBuilder::new(&b, tag_name);
|
||||
/// # fn flip_coin() -> bool { true }
|
||||
/// ```
|
||||
pub fn new(ctx: &'b NodeCtx<'a>, tag_name: &'static str) -> Self {
|
||||
let bump = ctx.bump();
|
||||
pub fn new(cx: &'b NodeCtx<'a>, tag_name: &'static str) -> Self {
|
||||
let bump = cx.bump();
|
||||
ElementBuilder {
|
||||
ctx,
|
||||
cx,
|
||||
key: NodeKey::NONE,
|
||||
tag_name,
|
||||
listeners: bumpalo::collections::Vec::new_in(bump),
|
||||
|
@ -124,7 +125,7 @@ where
|
|||
L: 'a + AsRef<[Listener<'a>]>,
|
||||
{
|
||||
ElementBuilder {
|
||||
ctx: self.ctx,
|
||||
cx: self.cx,
|
||||
key: self.key,
|
||||
tag_name: self.tag_name,
|
||||
listeners,
|
||||
|
@ -163,7 +164,7 @@ where
|
|||
A: 'a + AsRef<[Attribute<'a>]>,
|
||||
{
|
||||
ElementBuilder {
|
||||
ctx: self.ctx,
|
||||
cx: self.cx,
|
||||
key: self.key,
|
||||
tag_name: self.tag_name,
|
||||
listeners: self.listeners,
|
||||
|
@ -202,7 +203,7 @@ where
|
|||
C: 'a + AsRef<[VNode<'a>]>,
|
||||
{
|
||||
ElementBuilder {
|
||||
ctx: self.ctx,
|
||||
cx: self.cx,
|
||||
key: self.key,
|
||||
tag_name: self.tag_name,
|
||||
listeners: self.listeners,
|
||||
|
@ -227,9 +228,9 @@ where
|
|||
/// .finish();
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn namespace(self, namespace: Option<&'a str>) -> Self {
|
||||
pub fn namespace(self, namespace: Option<&'static str>) -> Self {
|
||||
ElementBuilder {
|
||||
ctx: self.ctx,
|
||||
cx: self.cx,
|
||||
key: self.key,
|
||||
tag_name: self.tag_name,
|
||||
listeners: self.listeners,
|
||||
|
@ -281,7 +282,7 @@ where
|
|||
Some(static_str) => static_str,
|
||||
None => {
|
||||
use bumpalo::core_alloc::fmt::Write;
|
||||
let mut s = bumpalo::collections::String::new_in(self.ctx.bump());
|
||||
let mut s = bumpalo::collections::String::new_in(self.cx.bump());
|
||||
s.write_fmt(args).unwrap();
|
||||
s.into_bump_str()
|
||||
}
|
||||
|
@ -307,7 +308,7 @@ where
|
|||
/// ```
|
||||
#[inline]
|
||||
pub fn finish(self) -> VNode<'a> {
|
||||
let bump = self.ctx.bump();
|
||||
let bump = self.cx.bump();
|
||||
|
||||
let children: &'a Children = bump.alloc(self.children);
|
||||
let children: &'a [VNode<'a>] = children.as_ref();
|
||||
|
@ -357,11 +358,11 @@ where
|
|||
/// .finish();
|
||||
/// ```
|
||||
pub fn on(self, event: &'static str, callback: impl Fn(VirtualEvent) + 'a) -> Self {
|
||||
let bump = &self.ctx.bump();
|
||||
let bump = &self.cx.bump();
|
||||
let listener = Listener {
|
||||
event,
|
||||
callback: bump.alloc(callback),
|
||||
scope: self.ctx.scope_ref.arena_idx,
|
||||
scope: self.cx.scope_ref.arena_idx,
|
||||
mounted_node: bump.alloc(Cell::new(RealDomNode::empty())),
|
||||
};
|
||||
self.add_listener(listener)
|
||||
|
@ -371,15 +372,15 @@ where
|
|||
self.listeners.push(listener);
|
||||
|
||||
// bump the context id forward
|
||||
let id = self.ctx.listener_id.get();
|
||||
self.ctx.listener_id.set(id + 1);
|
||||
let id = self.cx.listener_id.get();
|
||||
self.cx.listener_id.set(id + 1);
|
||||
|
||||
// Add this listener to the context list
|
||||
// This casts the listener to a self-referential pointer
|
||||
// This is okay because the bump arena is stable
|
||||
self.listeners.last().map(|g| {
|
||||
let r = unsafe { std::mem::transmute::<&Listener<'a>, &Listener<'static>>(g) };
|
||||
self.ctx
|
||||
self.cx
|
||||
.scope_ref
|
||||
.listeners
|
||||
.borrow_mut()
|
||||
|
@ -413,7 +414,7 @@ where
|
|||
Some(static_str) => static_str,
|
||||
None => {
|
||||
use bumpalo::core_alloc::fmt::Write;
|
||||
let mut s = bumpalo::collections::String::new_in(self.ctx.bump());
|
||||
let mut s = bumpalo::collections::String::new_in(self.cx.bump());
|
||||
s.write_fmt(args).unwrap();
|
||||
s.into_bump_str()
|
||||
}
|
||||
|
@ -501,7 +502,7 @@ where
|
|||
pub fn iter_child(mut self, nodes: impl IntoIterator<Item = impl IntoVNode<'a>>) -> Self {
|
||||
let len_before = self.children.len();
|
||||
for item in nodes {
|
||||
let child = item.into_vnode(&self.ctx);
|
||||
let child = item.into_vnode(&self.cx);
|
||||
self.children.push(child);
|
||||
}
|
||||
if cfg!(debug_assertions) {
|
||||
|
@ -531,20 +532,20 @@ impl<'a> IntoIterator for VNode<'a> {
|
|||
}
|
||||
}
|
||||
impl<'a> IntoVNode<'a> for VNode<'a> {
|
||||
fn into_vnode(self, ctx: &NodeCtx<'a>) -> VNode<'a> {
|
||||
fn into_vnode(self, cx: &NodeCtx<'a>) -> VNode<'a> {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoVNode<'a> for &VNode<'a> {
|
||||
fn into_vnode(self, ctx: &NodeCtx<'a>) -> VNode<'a> {
|
||||
fn into_vnode(self, cx: &NodeCtx<'a>) -> VNode<'a> {
|
||||
// cloning is cheap since vnodes are just references into bump arenas
|
||||
self.clone()
|
||||
}
|
||||
}
|
||||
|
||||
pub trait IntoVNode<'a> {
|
||||
fn into_vnode(self, ctx: &NodeCtx<'a>) -> VNode<'a>;
|
||||
fn into_vnode(self, cx: &NodeCtx<'a>) -> VNode<'a>;
|
||||
}
|
||||
|
||||
pub trait VNodeBuilder<'a, G>: IntoIterator<Item = G>
|
||||
|
@ -590,8 +591,8 @@ impl<'a, G> IntoVNode<'a> for LazyNodes<'a, G>
|
|||
where
|
||||
G: for<'b> FnOnce(&'b NodeCtx<'a>) -> VNode<'a> + 'a,
|
||||
{
|
||||
fn into_vnode(self, ctx: &NodeCtx<'a>) -> VNode<'a> {
|
||||
(self.inner)(ctx)
|
||||
fn into_vnode(self, cx: &NodeCtx<'a>) -> VNode<'a> {
|
||||
(self.inner)(cx)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -608,14 +609,14 @@ where
|
|||
}
|
||||
|
||||
impl<'a> IntoVNode<'a> for () {
|
||||
fn into_vnode(self, ctx: &NodeCtx<'a>) -> VNode<'a> {
|
||||
fn into_vnode(self, cx: &NodeCtx<'a>) -> VNode<'a> {
|
||||
todo!();
|
||||
VNode::Suspended
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoVNode<'a> for Option<()> {
|
||||
fn into_vnode(self, ctx: &NodeCtx<'a>) -> VNode<'a> {
|
||||
fn into_vnode(self, cx: &NodeCtx<'a>) -> VNode<'a> {
|
||||
todo!();
|
||||
VNode::Suspended
|
||||
}
|
||||
|
@ -679,7 +680,7 @@ pub fn attr<'a>(name: &'static str, value: &'a str) -> Attribute<'a> {
|
|||
}
|
||||
|
||||
pub fn virtual_child<'a, T: Properties + 'a>(
|
||||
ctx: &NodeCtx<'a>,
|
||||
cx: &NodeCtx<'a>,
|
||||
f: FC<T>,
|
||||
props: T,
|
||||
key: Option<&'a str>, // key: NodeKey<'a>,
|
||||
|
@ -689,37 +690,37 @@ pub fn virtual_child<'a, T: Properties + 'a>(
|
|||
// might override it with the props macro
|
||||
// todo!()
|
||||
VNode::Component(
|
||||
ctx.bump()
|
||||
.alloc(crate::nodes::VComponent::new(ctx, f, props, key, children)),
|
||||
// ctx.bump()
|
||||
cx.bump()
|
||||
.alloc(crate::nodes::VComponent::new(cx, f, props, key, children)),
|
||||
// cx.bump()
|
||||
// .alloc(crate::nodes::VComponent::new(f, props, key)),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn vfragment<'a>(
|
||||
ctx: &NodeCtx<'a>,
|
||||
cx: &NodeCtx<'a>,
|
||||
key: Option<&'a str>, // key: NodeKey<'a>,
|
||||
children: &'a [VNode<'a>],
|
||||
) -> VNode<'a> {
|
||||
VNode::Fragment(ctx.bump().alloc(VFragment::new(key, children)))
|
||||
VNode::Fragment(cx.bump().alloc(VFragment::new(key, children)))
|
||||
}
|
||||
|
||||
pub struct ChildrenList<'a, 'b> {
|
||||
ctx: &'b NodeCtx<'a>,
|
||||
cx: &'b NodeCtx<'a>,
|
||||
children: bumpalo::collections::Vec<'a, VNode<'a>>,
|
||||
}
|
||||
|
||||
impl<'a, 'b> ChildrenList<'a, 'b> {
|
||||
pub fn new(ctx: &'b NodeCtx<'a>) -> Self {
|
||||
pub fn new(cx: &'b NodeCtx<'a>) -> Self {
|
||||
Self {
|
||||
ctx,
|
||||
children: bumpalo::collections::Vec::new_in(ctx.bump()),
|
||||
cx,
|
||||
children: bumpalo::collections::Vec::new_in(cx.bump()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_child(mut self, nodes: impl IntoIterator<Item = impl IntoVNode<'a>>) -> Self {
|
||||
for item in nodes {
|
||||
let child = item.into_vnode(&self.ctx);
|
||||
let child = item.into_vnode(&self.cx);
|
||||
self.children.push(child);
|
||||
}
|
||||
self
|
||||
|
|
|
@ -11,10 +11,8 @@ use crate::{
|
|||
};
|
||||
use bumpalo::Bump;
|
||||
use std::{
|
||||
any::Any,
|
||||
cell::{Cell, RefCell},
|
||||
fmt::{Arguments, Debug, Formatter},
|
||||
marker::PhantomData,
|
||||
rc::Rc,
|
||||
};
|
||||
|
||||
|
@ -56,6 +54,43 @@ impl<'a> Clone for VNode<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'old, 'new> VNode<'old> {
|
||||
// performs a somewhat costly clone of this vnode into another bump
|
||||
// this is used when you want to drag nodes from an old frame into a new frame
|
||||
// There is no way to safely drag listeners over (no way to clone a closure)
|
||||
//
|
||||
// This method will only be called if a component was once a real node and then becomes suspended
|
||||
fn deep_clone_to_new_bump(&self, new: &'new Bump) -> VNode<'new> {
|
||||
match self {
|
||||
VNode::Element(el) => {
|
||||
let new_el: VElement<'new> = VElement {
|
||||
key: NodeKey::NONE,
|
||||
// key: el.key.clone(),
|
||||
tag_name: el.tag_name,
|
||||
// wipe listeners on deep clone, there's no way to know what other bump material they might be referencing (nodes, etc)
|
||||
listeners: &[],
|
||||
attributes: {
|
||||
let attr_vec = bumpalo::collections::Vec::new_in(new);
|
||||
attr_vec.into_bump_slice()
|
||||
},
|
||||
children: {
|
||||
let attr_vec = bumpalo::collections::Vec::new_in(new);
|
||||
attr_vec.into_bump_slice()
|
||||
},
|
||||
namespace: el.namespace.clone(),
|
||||
dom_id: el.dom_id.clone(),
|
||||
};
|
||||
|
||||
VNode::Element(new.alloc_with(move || new_el))
|
||||
}
|
||||
VNode::Text(_) => todo!(),
|
||||
VNode::Fragment(_) => todo!(),
|
||||
VNode::Suspended => todo!(),
|
||||
VNode::Component(_) => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> VNode<'a> {
|
||||
/// Low-level constructor for making a new `Node` of type element with given
|
||||
/// parts.
|
||||
|
@ -67,11 +102,11 @@ impl<'a> VNode<'a> {
|
|||
pub fn element(
|
||||
bump: &'a Bump,
|
||||
key: NodeKey<'a>,
|
||||
tag_name: &'a str,
|
||||
tag_name: &'static str,
|
||||
listeners: &'a [Listener<'a>],
|
||||
attributes: &'a [Attribute<'a>],
|
||||
children: &'a [VNode<'a>],
|
||||
namespace: Option<&'a str>,
|
||||
namespace: Option<&'static str>,
|
||||
) -> VNode<'a> {
|
||||
let element = bump.alloc_with(|| VElement {
|
||||
key,
|
||||
|
@ -157,14 +192,16 @@ pub struct VText<'src> {
|
|||
// ========================================================
|
||||
// VElement (div, h1, etc), attrs, keys, listener handle
|
||||
// ========================================================
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct VElement<'a> {
|
||||
/// Elements have a tag name, zero or more attributes, and zero or more
|
||||
pub key: NodeKey<'a>,
|
||||
pub tag_name: &'a str,
|
||||
pub tag_name: &'static str,
|
||||
pub listeners: &'a [Listener<'a>],
|
||||
pub attributes: &'a [Attribute<'a>],
|
||||
pub children: &'a [VNode<'a>],
|
||||
pub namespace: Option<&'a str>,
|
||||
pub namespace: Option<&'static str>,
|
||||
pub dom_id: Cell<RealDomNode>,
|
||||
}
|
||||
|
||||
|
@ -298,13 +335,13 @@ impl<'a> VComponent<'a> {
|
|||
///
|
||||
/// If the CanMemo is `false`, then the macro will call the backup method which always defaults to "false"
|
||||
pub fn new<P: Properties + 'a>(
|
||||
ctx: &NodeCtx<'a>,
|
||||
cx: &NodeCtx<'a>,
|
||||
component: FC<P>,
|
||||
props: P,
|
||||
key: Option<&'a str>,
|
||||
children: &'a [VNode<'a>],
|
||||
) -> Self {
|
||||
let bump = ctx.bump();
|
||||
let bump = cx.bump();
|
||||
let user_fc = component as *const ();
|
||||
|
||||
let props = bump.alloc(props);
|
||||
|
@ -370,13 +407,13 @@ fn create_closure<'a, P: 'a>(
|
|||
let g: Captured = Rc::new(move |scp: &Scope| -> VNode {
|
||||
// cast back into the right lifetime
|
||||
let safe_props: &'_ P = unsafe { &*(raw_props as *const P) };
|
||||
// let ctx: Context<P2> = todo!();
|
||||
let ctx: Context<P> = Context {
|
||||
// let cx: Context<P2> = todo!();
|
||||
let cx: Context<P> = Context {
|
||||
props: safe_props,
|
||||
scope: scp,
|
||||
};
|
||||
|
||||
let g = component(ctx);
|
||||
let g = component(cx);
|
||||
let g2 = unsafe { std::mem::transmute(g) };
|
||||
g2
|
||||
});
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
use crate::{arena::ScopeArena, innerlude::*};
|
||||
use bumpalo::Bump;
|
||||
use futures::FutureExt;
|
||||
use generational_arena::Arena;
|
||||
use std::{
|
||||
any::{Any, TypeId},
|
||||
|
@ -55,7 +56,7 @@ pub struct VirtualDom {
|
|||
#[doc(hidden)]
|
||||
_root_caller: Rc<OpaqueComponent>,
|
||||
// _root_caller: Rc<OpaqueComponent<'static>>,
|
||||
/// Type of the original ctx. This is stored as TypeId so VirtualDom does not need to be generic.
|
||||
/// Type of the original cx. This is stored as TypeId so VirtualDom does not need to be generic.
|
||||
///
|
||||
/// Whenver props need to be updated, an Error will be thrown if the new props do not
|
||||
/// match the props used to create the VirtualDom.
|
||||
|
@ -90,12 +91,12 @@ impl VirtualDom {
|
|||
/// ```ignore
|
||||
/// // Directly from a closure
|
||||
///
|
||||
/// let dom = VirtualDom::new(|ctx| ctx.render(rsx!{ div {"hello world"} }));
|
||||
/// let dom = VirtualDom::new(|cx| cx.render(rsx!{ div {"hello world"} }));
|
||||
///
|
||||
/// // or pass in...
|
||||
///
|
||||
/// let root = |ctx| {
|
||||
/// ctx.render(rsx!{
|
||||
/// let root = |cx| {
|
||||
/// cx.render(rsx!{
|
||||
/// div {"hello world"}
|
||||
/// })
|
||||
/// }
|
||||
|
@ -103,8 +104,8 @@ impl VirtualDom {
|
|||
///
|
||||
/// // or directly from a fn
|
||||
///
|
||||
/// fn Example(ctx: Context<()>) -> VNode {
|
||||
/// ctx.render(rsx!{ div{"hello world"} })
|
||||
/// fn Example(cx: Context<()>) -> VNode {
|
||||
/// cx.render(rsx!{ div{"hello world"} })
|
||||
/// }
|
||||
///
|
||||
/// let dom = VirtualDom::new(Example);
|
||||
|
@ -113,7 +114,7 @@ impl VirtualDom {
|
|||
Self::new_with_props(root, ())
|
||||
}
|
||||
|
||||
/// Start a new VirtualDom instance with a dependent ctx.
|
||||
/// Start a new VirtualDom instance with a dependent cx.
|
||||
/// Later, the props can be updated by calling "update" with a new set of props, causing a set of re-renders.
|
||||
///
|
||||
/// This is useful when a component tree can be driven by external state (IE SSR) but it would be too expensive
|
||||
|
@ -122,12 +123,12 @@ impl VirtualDom {
|
|||
/// ```ignore
|
||||
/// // Directly from a closure
|
||||
///
|
||||
/// let dom = VirtualDom::new(|ctx| ctx.render(rsx!{ div {"hello world"} }));
|
||||
/// let dom = VirtualDom::new(|cx| cx.render(rsx!{ div {"hello world"} }));
|
||||
///
|
||||
/// // or pass in...
|
||||
///
|
||||
/// let root = |ctx| {
|
||||
/// ctx.render(rsx!{
|
||||
/// let root = |cx| {
|
||||
/// cx.render(rsx!{
|
||||
/// div {"hello world"}
|
||||
/// })
|
||||
/// }
|
||||
|
@ -135,8 +136,8 @@ impl VirtualDom {
|
|||
///
|
||||
/// // or directly from a fn
|
||||
///
|
||||
/// fn Example(ctx: Context, props: &SomeProps) -> VNode {
|
||||
/// ctx.render(rsx!{ div{"hello world"} })
|
||||
/// fn Example(cx: Context, props: &SomeProps) -> VNode {
|
||||
/// cx.render(rsx!{ div{"hello world"} })
|
||||
/// }
|
||||
///
|
||||
/// let dom = VirtualDom::new(Example);
|
||||
|
@ -395,11 +396,13 @@ pub struct Scope {
|
|||
// Stores references into the listeners attached to the vnodes
|
||||
// NEEDS TO BE PRIVATE
|
||||
pub(crate) listeners: RefCell<Vec<(*const Cell<RealDomNode>, *const dyn Fn(VirtualEvent))>>,
|
||||
|
||||
pub(crate) suspended_tasks: Vec<Box<dyn Future<Output = VNode<'static>>>>,
|
||||
// pub(crate) listeners: RefCell<nohash_hasher::IntMap<u32, *const dyn Fn(VirtualEvent)>>,
|
||||
// pub(crate) listeners: RefCell<Vec<*const dyn Fn(VirtualEvent)>>,
|
||||
// pub(crate) listeners: RefCell<Vec<*const dyn Fn(VirtualEvent)>>,
|
||||
// NoHashMap<RealDomNode, <*const dyn Fn(VirtualEvent)>
|
||||
// pub(crate) listeners: RefCell<Vec<*const dyn Fn(VirtualEvent)>>,
|
||||
// pub(crate) listeners: RefCell<Vec<*const dyn Fn(VirtualEvent)>>
|
||||
}
|
||||
|
||||
// We need to pin the hook so it doesn't move as we initialize the list of hooks
|
||||
|
@ -465,6 +468,7 @@ impl Scope {
|
|||
listeners: Default::default(),
|
||||
hookidx: Default::default(),
|
||||
descendents: Default::default(),
|
||||
suspended_tasks: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -588,9 +592,9 @@ impl Scope {
|
|||
///
|
||||
/// }
|
||||
///
|
||||
/// fn example(ctx: Context, props: &Props -> VNode {
|
||||
/// fn example(cx: Context, props: &Props -> VNode {
|
||||
/// html! {
|
||||
/// <div> "Hello, {ctx.ctx.name}" </div>
|
||||
/// <div> "Hello, {cx.cx.name}" </div>
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
|
@ -645,6 +649,14 @@ pub trait Scoped<'src>: Sized {
|
|||
self.get_scope().event_channel.clone()
|
||||
}
|
||||
|
||||
fn schedule_effect(&self) -> Rc<dyn Fn() + 'static> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn schedule_layout_effect(&self) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Take a lazy VNode structure and actually build it with the context of the VDom's efficient VNode allocator.
|
||||
///
|
||||
/// This function consumes the context and absorb the lifetime, so these VNodes *must* be returned.
|
||||
|
@ -652,12 +664,12 @@ pub trait Scoped<'src>: Sized {
|
|||
/// ## Example
|
||||
///
|
||||
/// ```ignore
|
||||
/// fn Component(ctx: Context<()>) -> VNode {
|
||||
/// fn Component(cx: Context<()>) -> VNode {
|
||||
/// // Lazy assemble the VNode tree
|
||||
/// let lazy_tree = html! {<div> "Hello World" </div>};
|
||||
///
|
||||
/// // Actually build the tree and allocate it
|
||||
/// ctx.render(lazy_tree)
|
||||
/// cx.render(lazy_tree)
|
||||
/// }
|
||||
///```
|
||||
fn render<'a, F: for<'b> FnOnce(&'b NodeCtx<'src>) -> VNode<'src> + 'src + 'a>(
|
||||
|
@ -750,7 +762,7 @@ Any function prefixed with "use" should not be called conditionally.
|
|||
///
|
||||
fn use_create_context<T: 'static>(&self, init: impl Fn() -> T) {
|
||||
let scope = self.get_scope();
|
||||
let mut ctxs = scope.shared_contexts.borrow_mut();
|
||||
let mut cxs = scope.shared_contexts.borrow_mut();
|
||||
let ty = TypeId::of::<T>();
|
||||
|
||||
let is_initialized = self.use_hook(
|
||||
|
@ -763,14 +775,14 @@ Any function prefixed with "use" should not be called conditionally.
|
|||
|_| {},
|
||||
);
|
||||
|
||||
match (is_initialized, ctxs.contains_key(&ty)) {
|
||||
match (is_initialized, cxs.contains_key(&ty)) {
|
||||
// Do nothing, already initialized and already exists
|
||||
(true, true) => {}
|
||||
|
||||
// Needs to be initialized
|
||||
(false, false) => {
|
||||
log::debug!("Initializing context...");
|
||||
ctxs.insert(ty, Rc::new(init()));
|
||||
cxs.insert(ty, Rc::new(init()));
|
||||
}
|
||||
|
||||
_ => debug_assert!(false, "Cannot initialize two contexts of the same type"),
|
||||
|
@ -810,9 +822,9 @@ Any function prefixed with "use" should not be called conditionally.
|
|||
log::debug!("Searching {:#?} for valid shared_context", inner.arena_idx);
|
||||
let shared_contexts = inner.shared_contexts.borrow();
|
||||
|
||||
if let Some(shared_ctx) = shared_contexts.get(&ty) {
|
||||
log::debug!("found matching ctx");
|
||||
let rc = shared_ctx
|
||||
if let Some(shared_cx) = shared_contexts.get(&ty) {
|
||||
log::debug!("found matching cx");
|
||||
let rc = shared_cx
|
||||
.clone()
|
||||
.downcast::<T>()
|
||||
.expect("Should not fail, already validated the type from the hashmap");
|
||||
|
@ -841,10 +853,32 @@ Any function prefixed with "use" should not be called conditionally.
|
|||
)
|
||||
}
|
||||
|
||||
fn suspend<O>(
|
||||
fn suspend<O: 'src>(
|
||||
&self,
|
||||
f: impl Future<Output = O>,
|
||||
g: impl FnOnce(O) -> VNode<'src> + 'src,
|
||||
f: &'src mut Pin<Box<dyn Future<Output = O> + Send + 'static>>,
|
||||
g: impl FnOnce(SuspendedContext, O) -> VNode<'src> + 'src,
|
||||
) -> VNode<'src> {
|
||||
match f.now_or_never() {
|
||||
Some(o) => {
|
||||
let suspended_cx = SuspendedContext {};
|
||||
let nodes = g(suspended_cx, o);
|
||||
return nodes;
|
||||
}
|
||||
None => {
|
||||
// we need to register this task
|
||||
VNode::Suspended
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct SuspendedContext {}
|
||||
|
||||
impl SuspendedContext {
|
||||
pub fn render<'a, 'src, F: for<'b> FnOnce(&'b NodeCtx<'src>) -> VNode<'src> + 'src + 'a>(
|
||||
self,
|
||||
lazy_nodes: LazyNodes<'src, F>,
|
||||
) -> VNode<'src> {
|
||||
todo!()
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use dioxus_ssr::prelude::*;
|
||||
|
||||
pub static Blog: FC<()> = |ctx| {
|
||||
rsx! { in ctx,
|
||||
pub static Blog: FC<()> = |cx| {
|
||||
rsx! { in cx,
|
||||
div {
|
||||
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use dioxus_ssr::prelude::*;
|
||||
|
||||
pub static Community: FC<()> = |ctx| {
|
||||
rsx! { in ctx,
|
||||
pub static Community: FC<()> = |cx| {
|
||||
rsx! { in cx,
|
||||
div {
|
||||
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use dioxus_ssr::prelude::*;
|
||||
|
||||
pub static Docs: FC<()> = |ctx| {
|
||||
rsx! { in ctx,
|
||||
pub static Docs: FC<()> = |cx| {
|
||||
rsx! { in cx,
|
||||
div {
|
||||
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ const HeroContent: [(&'static str, &'static str); 3] = [
|
|||
|
||||
const SnippetHighlights: &'static str = include_str!("./../snippets.md");
|
||||
|
||||
pub static Home: FC<()> = |ctx| {
|
||||
pub static Home: FC<()> = |cx| {
|
||||
let hero = HeroContent.iter().map(|(title, body)| {
|
||||
rsx! {
|
||||
div {
|
||||
|
@ -20,9 +20,9 @@ pub static Home: FC<()> = |ctx| {
|
|||
}
|
||||
}
|
||||
});
|
||||
let snippets: Vec<VNode> = crate::utils::markdown_to_snippet(ctx, SnippetHighlights);
|
||||
let snippets: Vec<VNode> = crate::utils::markdown_to_snippet(cx, SnippetHighlights);
|
||||
|
||||
rsx! { in ctx,
|
||||
rsx! { in cx,
|
||||
div {
|
||||
header {
|
||||
// Hero
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use dioxus_ssr::prelude::*;
|
||||
|
||||
pub static Tutorial: FC<()> = |ctx| {
|
||||
rsx! { in ctx,
|
||||
pub static Tutorial: FC<()> = |cx| {
|
||||
rsx! { in cx,
|
||||
div {
|
||||
|
||||
}
|
||||
|
|
|
@ -24,18 +24,18 @@ fn main() {
|
|||
*/
|
||||
}
|
||||
|
||||
static App: FC<()> = |ctx| {
|
||||
let (url, set_url) = use_state(&ctx, || "");
|
||||
static App: FC<()> = |cx| {
|
||||
let (url, set_url) = use_state(&cx, || "");
|
||||
|
||||
let body = match *url {
|
||||
"community" => rsx!(in ctx, Community {}),
|
||||
"tutorial" => rsx!(in ctx, Tutorial {}),
|
||||
"blog" => rsx!(in ctx, Blog {}),
|
||||
"docs" => rsx!(in ctx, Docs {}),
|
||||
_ => rsx!(in ctx, Home {}),
|
||||
"community" => rsx!(in cx, Community {}),
|
||||
"tutorial" => rsx!(in cx, Tutorial {}),
|
||||
"blog" => rsx!(in cx, Blog {}),
|
||||
"docs" => rsx!(in cx, Docs {}),
|
||||
_ => rsx!(in cx, Home {}),
|
||||
};
|
||||
|
||||
ctx.render(rsx! {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
NavBar {}
|
||||
{body}
|
||||
|
@ -44,8 +44,8 @@ static App: FC<()> = |ctx| {
|
|||
})
|
||||
};
|
||||
|
||||
static NavBar: FC<()> = |ctx| {
|
||||
ctx.render(rsx! {
|
||||
static NavBar: FC<()> = |cx| {
|
||||
cx.render(rsx! {
|
||||
header {
|
||||
a {
|
||||
href: "/"
|
||||
|
@ -99,7 +99,7 @@ static SECTIONS: &[(&str, &[(&str, &str)])] = &[
|
|||
),
|
||||
];
|
||||
|
||||
fn Footer(ctx: Context<()>) -> VNode {
|
||||
fn Footer(cx: Context<()>) -> VNode {
|
||||
let sections = SECTIONS.iter().map(|(section, raw_links)| {
|
||||
let links = raw_links.iter().map(|(link_name, href)| {
|
||||
rsx! (
|
||||
|
@ -117,7 +117,7 @@ fn Footer(ctx: Context<()>) -> VNode {
|
|||
}
|
||||
});
|
||||
|
||||
ctx.render(rsx! {
|
||||
cx.render(rsx! {
|
||||
footer {
|
||||
div {
|
||||
div {
|
||||
|
@ -136,8 +136,8 @@ fn Footer(ctx: Context<()>) -> VNode {
|
|||
})
|
||||
}
|
||||
|
||||
const ExternalLinkIcon: FC<()> = |ctx| {
|
||||
ctx.render(html! {
|
||||
const ExternalLinkIcon: FC<()> = |cx| {
|
||||
cx.render(html! {
|
||||
<svg x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15">
|
||||
<path
|
||||
fill="currentColor"
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
#[derive(PartialEq, Properties)]
|
||||
struct Props { name: &'static str }
|
||||
|
||||
static HelloMessage: FC<Props> = |ctx| {
|
||||
ctx.render(rsx!{
|
||||
div { "Hello {ctx.props.name}" }
|
||||
static HelloMessage: FC<Props> = |cx| {
|
||||
cx.render(rsx!{
|
||||
div { "Hello {cx.props.name}" }
|
||||
})
|
||||
}
|
||||
```
|
||||
|
@ -16,8 +16,8 @@ static HelloMessage: FC<Props> = |ctx| {
|
|||
Choose from a close-to-html syntax or the standard rsx! syntax
|
||||
|
||||
```rust
|
||||
static HelloMessage: FC<()> = |ctx| {
|
||||
ctx.render(html!{
|
||||
static HelloMessage: FC<()> = |cx| {
|
||||
cx.render(html!{
|
||||
<div> Hello World! </div>
|
||||
})
|
||||
}
|
||||
|
@ -33,8 +33,8 @@ enum LightState {
|
|||
Yellow,
|
||||
Red,
|
||||
}
|
||||
static HelloMessage: FC<()> = |ctx| {
|
||||
let (color, set_color) = use_state(&ctx, || LightState::Green);
|
||||
static HelloMessage: FC<()> = |cx| {
|
||||
let (color, set_color) = use_state(&cx, || LightState::Green);
|
||||
|
||||
let title = match color {
|
||||
Green => "Green means go",
|
||||
|
@ -42,7 +42,7 @@ static HelloMessage: FC<()> = |ctx| {
|
|||
Red => "Red means stop",
|
||||
};
|
||||
|
||||
ctx.render(rsx!{
|
||||
cx.render(rsx!{
|
||||
h1 { "{title}" }
|
||||
button { "tick"
|
||||
onclick: move |_| set_color(match color {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use dioxus_ssr::prelude::{Context, VNode};
|
||||
|
||||
// Parse a snippet into
|
||||
pub fn markdown_to_snippet<'a, P>(ctx: Context<'a, P>, text: &str) -> Vec<VNode<'a>> {
|
||||
pub fn markdown_to_snippet<'a, P>(cx: Context<'a, P>, text: &str) -> Vec<VNode<'a>> {
|
||||
let snips = Vec::new();
|
||||
use pulldown_cmark::{Options, Parser};
|
||||
let mut options = Options::empty();
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
|
||||
|
||||
fn main() {
|
||||
// let mut s = Context { props: &() };
|
||||
// let g = Component(&mut s);
|
||||
|
@ -15,9 +13,9 @@ fn main() {
|
|||
// Remvoe,
|
||||
// }
|
||||
|
||||
// static Component: FC<()> = |ctx| {
|
||||
// static Component: FC<()> = |cx| {
|
||||
// let (tasks, dispatch) = use_reducer(
|
||||
// ctx,
|
||||
// cx,
|
||||
// || CompState { tasks: Vec::new() },
|
||||
// |state, action: Actions| match action {
|
||||
// Actions::Add => state,
|
||||
|
@ -48,7 +46,7 @@ fn main() {
|
|||
// };
|
||||
|
||||
// fn use_reducer<Props, State, Action>(
|
||||
// ctx: &mut Context<Props>,
|
||||
// cx: &mut Context<Props>,
|
||||
// init: fn() -> State,
|
||||
// reducer: fn(State, Action) -> State,
|
||||
// ) -> (State, impl Fn(Action)) {
|
||||
|
|
|
@ -20,7 +20,7 @@ This is moderately efficient because the fields of the map are moved, but the da
|
|||
However, if you used similar approach with Dioxus:
|
||||
|
||||
```rust
|
||||
let (map, set_map) = use_state(&ctx, || HashMap::new());
|
||||
let (map, set_map) = use_state(&cx, || HashMap::new());
|
||||
set_map({
|
||||
let mut newmap = map.clone();
|
||||
newmap.set(key, value);
|
||||
|
@ -40,11 +40,11 @@ uses the same memoization on top of the use_context API.
|
|||
|
||||
Here's a fully-functional todo app using the use_map API:
|
||||
```rust
|
||||
static TodoList: FC<()> = |ctx| {
|
||||
let todos = use_map(ctx, || HashMap::new());
|
||||
static TodoList: FC<()> = |cx| {
|
||||
let todos = use_map(cx, || HashMap::new());
|
||||
let input = use_ref(|| None);
|
||||
|
||||
ctx.render(rsx!{
|
||||
cx.render(rsx!{
|
||||
div {
|
||||
button {
|
||||
"Add todo"
|
||||
|
@ -84,10 +84,10 @@ fn use_map() {}
|
|||
// Elements are received as Rc<T> in case the underlying collection is shuffled around
|
||||
// Setters/getters can be generated
|
||||
fn use_collection<'a, T: Collection>(
|
||||
ctx: &impl Scoped<'a>,
|
||||
cx: &impl Scoped<'a>,
|
||||
f: impl Fn() -> T,
|
||||
) -> CollectionHandle<'a, T> {
|
||||
ctx.use_hook(
|
||||
cx.use_hook(
|
||||
|| {},
|
||||
|h| {
|
||||
//
|
||||
|
|
|
@ -27,13 +27,13 @@ mod client {
|
|||
Ok(dioxus_web::WebsysRenderer::start(APP).await)
|
||||
}
|
||||
|
||||
static APP: FC<()> = |ctx| {
|
||||
static APP: FC<()> = |cx| {
|
||||
todo!()
|
||||
// let (selected_stream, set_stream) = use_state(&ctx, || SelectedStream::Football);
|
||||
// let (selected_stream, set_stream) = use_state(&cx, || SelectedStream::Football);
|
||||
|
||||
// let opts = SelectedStream::iter().map(|name| rsx! { option { "{name}", value: "{name}" } });
|
||||
|
||||
// ctx.render(rsx! {
|
||||
// cx.render(rsx! {
|
||||
// div {
|
||||
// h1 { "Tide basic CRUD app" }
|
||||
// h2 { "Chosen stream: {selected_stream}" }
|
||||
|
@ -102,27 +102,27 @@ mod server {
|
|||
selected_stream: SelectedStream,
|
||||
}
|
||||
|
||||
static STREAM_LIST: FC<SreamListProps> = |ctx| {
|
||||
static STREAM_LIST: FC<SreamListProps> = |cx| {
|
||||
//
|
||||
let g = match ctx.selected_stream {
|
||||
SelectedStream::Football => ctx.render(rsx! {
|
||||
let g = match cx.selected_stream {
|
||||
SelectedStream::Football => cx.render(rsx! {
|
||||
li {
|
||||
"watch football!"
|
||||
}
|
||||
}),
|
||||
SelectedStream::Hockey => ctx.render(rsx! {
|
||||
SelectedStream::Hockey => cx.render(rsx! {
|
||||
li {
|
||||
"watch football!"
|
||||
}
|
||||
}),
|
||||
SelectedStream::Socker => ctx.render(rsx! {
|
||||
SelectedStream::Socker => cx.render(rsx! {
|
||||
li {
|
||||
"watch football!"
|
||||
}
|
||||
}),
|
||||
};
|
||||
|
||||
ctx.render(rsx! {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
|
||||
}
|
||||
|
|
|
@ -27,13 +27,13 @@ mod client {
|
|||
Ok(dioxus_web::WebsysRenderer::start(APP).await)
|
||||
}
|
||||
|
||||
static APP: FC<()> = |ctx| {
|
||||
static APP: FC<()> = |cx| {
|
||||
todo!()
|
||||
// let (selected_stream, set_stream) = use_state(&ctx, || SelectedStream::Football);
|
||||
// let (selected_stream, set_stream) = use_state(&cx, || SelectedStream::Football);
|
||||
|
||||
// let opts = SelectedStream::iter().map(|name| rsx! { option { "{name}", value: "{name}" } });
|
||||
|
||||
// ctx.render(rsx! {
|
||||
// cx.render(rsx! {
|
||||
// div {
|
||||
// h1 { "Tide basic CRUD app" }
|
||||
// h2 { "Chosen stream: {selected_stream}" }
|
||||
|
@ -102,29 +102,29 @@ mod server {
|
|||
selected_stream: SelectedStream,
|
||||
}
|
||||
|
||||
static STREAM_LIST: FC<SreamListProps> = |ctx| {
|
||||
static STREAM_LIST: FC<SreamListProps> = |cx| {
|
||||
//
|
||||
match ctx.selected_stream {
|
||||
SelectedStream::Football => ctx.render(rsx! {
|
||||
match cx.selected_stream {
|
||||
SelectedStream::Football => cx.render(rsx! {
|
||||
li {
|
||||
"watch football!"
|
||||
}
|
||||
}),
|
||||
|
||||
_ => unimplemented!()
|
||||
// .render(ctx),
|
||||
// .render(cx),
|
||||
// SelectedStream::Hockey => rsx! {
|
||||
// li {
|
||||
// "watch football!"
|
||||
// }
|
||||
// }
|
||||
// .render(ctx),
|
||||
// .render(cx),
|
||||
// SelectedStream::Socker => rsx! {
|
||||
// li {
|
||||
// "watch football!"
|
||||
// }
|
||||
// }
|
||||
// .render(ctx),
|
||||
// .render(cx),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -145,21 +145,21 @@ mod ergorsx {
|
|||
// }
|
||||
|
||||
// trait Renderable {
|
||||
// fn render(self, nodectx: &Ncx) -> VVNode;
|
||||
// fn render(self, nodecx: &Ncx) -> VVNode;
|
||||
// }
|
||||
|
||||
// impl<F: Fn(&Ncx) -> VVNode> Renderable for DTree<F> {
|
||||
// fn render(self, nodectx: &Ncx) -> VVNode {
|
||||
// (self.caller)(nodectx)
|
||||
// fn render(self, nodecx: &Ncx) -> VVNode {
|
||||
// (self.caller)(nodecx)
|
||||
// }
|
||||
// }
|
||||
|
||||
// fn test() {
|
||||
// let t = 123;
|
||||
// let r = match t {
|
||||
// 123 => DTree::new(|f| VVNode {}).render(ctx),
|
||||
// 456 => DTree::new(|f| VVNode {}).render(ctx),
|
||||
// 789 => DTree::new(|f| VVNode {}).render(ctx),
|
||||
// 123 => DTree::new(|f| VVNode {}).render(cx),
|
||||
// 456 => DTree::new(|f| VVNode {}).render(cx),
|
||||
// 789 => DTree::new(|f| VVNode {}).render(cx),
|
||||
// _ => unreachable!(),
|
||||
// };
|
||||
// }
|
||||
|
@ -169,11 +169,11 @@ mod ergorsx {
|
|||
// div {
|
||||
|
||||
// }
|
||||
// }.render(ctx)
|
||||
// }.render(cx)
|
||||
// }
|
||||
|
||||
// fn example() {
|
||||
// ctx.render(rsx!{
|
||||
// cx.render(rsx!{
|
||||
// div {
|
||||
|
||||
// }
|
||||
|
|
|
@ -9,11 +9,11 @@ Using the router should feel similar to tide's routing framework where an "addre
|
|||
Here's an example of how to use the router hook:
|
||||
|
||||
```rust
|
||||
static App: FC<()> = |ctx| {
|
||||
static App: FC<()> = |cx| {
|
||||
|
||||
// Route returns the associated VNodes
|
||||
// This hook re-fires when the route changes
|
||||
let route = use_router(ctx, |router| {
|
||||
let route = use_router(cx, |router| {
|
||||
router.at("/").get(|path| {
|
||||
rsx!{ <LandingPage /> }
|
||||
});
|
||||
|
@ -27,7 +27,7 @@ static App: FC<()> = |ctx| {
|
|||
});
|
||||
});
|
||||
|
||||
ctx.render(rsx!{
|
||||
cx.render(rsx!{
|
||||
div {
|
||||
Navbar {}
|
||||
{route}
|
||||
|
|
|
@ -14,8 +14,8 @@ struct ExampleProps {
|
|||
initial_name: String,
|
||||
}
|
||||
|
||||
static Example: FC<ExampleProps> = |ctx| {
|
||||
let dispaly_name = use_state_new(&ctx, move || ctx.initial_name.clone());
|
||||
static Example: FC<ExampleProps> = |cx| {
|
||||
let dispaly_name = use_state_new(&cx, move || cx.initial_name.clone());
|
||||
|
||||
let buttons = ["Jack", "Jill", "Bob"].iter().map(|name| {
|
||||
rsx!{
|
||||
|
@ -27,7 +27,7 @@ static Example: FC<ExampleProps> = |ctx| {
|
|||
}
|
||||
});
|
||||
|
||||
ctx.render(rsx! {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
class: "py-12 px-4 text-center w-full max-w-2xl mx-auto",
|
||||
// classes: [Some("asd")]
|
||||
|
|
|
@ -53,11 +53,11 @@ fn html_render(
|
|||
|
||||
#[test]
|
||||
fn test_serialize() {
|
||||
let mut dom = VirtualDom::new(|ctx| {
|
||||
let mut dom = VirtualDom::new(|cx| {
|
||||
//
|
||||
//
|
||||
//
|
||||
ctx.render(rsx! {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
title: "About W3Schools"
|
||||
{(0..20).map(|f| rsx!{
|
||||
|
|
|
@ -13,8 +13,8 @@ fn main() {
|
|||
wasm_bindgen_futures::spawn_local(WebsysRenderer::start(App));
|
||||
}
|
||||
|
||||
static App: FC<()> = |ctx| {
|
||||
ctx.render(rsx! {
|
||||
static App: FC<()> = |cx| {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
h1 {"hello"}
|
||||
C1 {}
|
||||
|
@ -23,23 +23,23 @@ static App: FC<()> = |ctx| {
|
|||
})
|
||||
};
|
||||
|
||||
static C1: FC<()> = |ctx| {
|
||||
ctx.render(rsx! {
|
||||
static C1: FC<()> = |cx| {
|
||||
cx.render(rsx! {
|
||||
button {
|
||||
"numba 1"
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
static C2: FC<()> = |ctx| {
|
||||
ctx.render(rsx! {
|
||||
static C2: FC<()> = |cx| {
|
||||
cx.render(rsx! {
|
||||
button {
|
||||
"numba 2"
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
static DocExamples: FC<()> = |ctx| {
|
||||
static DocExamples: FC<()> = |cx| {
|
||||
//
|
||||
|
||||
let is_ready = false;
|
||||
|
@ -61,7 +61,7 @@ static DocExamples: FC<()> = |ctx| {
|
|||
// }
|
||||
// }
|
||||
|
||||
ctx.render(rsx! {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
{ is_ready.then(|| rsx!{ h1 {"We are ready!"} }) }
|
||||
}
|
||||
|
|
|
@ -12,8 +12,8 @@ fn main() {
|
|||
wasm_bindgen_futures::spawn_local(WebsysRenderer::start(App));
|
||||
}
|
||||
|
||||
static App: FC<()> = |ctx| {
|
||||
ctx.render(rsx! {
|
||||
static App: FC<()> = |cx| {
|
||||
cx.render(rsx! {
|
||||
Calcier {
|
||||
h2 {"abc 1"}
|
||||
h2 {"abc 2"}
|
||||
|
@ -24,13 +24,13 @@ static App: FC<()> = |ctx| {
|
|||
})
|
||||
};
|
||||
|
||||
static Calcier: FC<()> = |ctx| {
|
||||
ctx.render(rsx! {
|
||||
static Calcier: FC<()> = |cx| {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
h1 {
|
||||
"abc 0"
|
||||
}
|
||||
{ctx.children()}
|
||||
{cx.children()}
|
||||
}
|
||||
})
|
||||
};
|
||||
|
|
|
@ -24,10 +24,10 @@ fn main() {
|
|||
#[derive(Debug)]
|
||||
struct CustomContext([&'static str; 3]);
|
||||
|
||||
static Example: FC<()> = |ctx| {
|
||||
ctx.use_create_context(|| CustomContext(["Jack", "Jill", "Bob"]));
|
||||
static Example: FC<()> = |cx| {
|
||||
cx.use_create_context(|| CustomContext(["Jack", "Jill", "Bob"]));
|
||||
|
||||
ctx.render(rsx! {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
class: "py-12 px-4 text-center w-full max-w-2xl mx-auto"
|
||||
span {
|
||||
|
@ -51,11 +51,11 @@ struct ButtonProps {
|
|||
id: u8,
|
||||
}
|
||||
|
||||
fn CustomButton(ctx: Context<ButtonProps>) -> VNode {
|
||||
let names = ctx.use_context::<CustomContext>();
|
||||
let name = names.0[ctx.id as usize];
|
||||
fn CustomButton(cx: Context<ButtonProps>) -> VNode {
|
||||
let names = cx.use_context::<CustomContext>();
|
||||
let name = names.0[cx.id as usize];
|
||||
|
||||
ctx.render(rsx!{
|
||||
cx.render(rsx!{
|
||||
button {
|
||||
class: "inline-block py-4 px-8 mr-6 leading-none text-white bg-indigo-600 hover:bg-indigo-900 font-semibold rounded shadow"
|
||||
"{name}"
|
||||
|
|
|
@ -10,10 +10,10 @@ fn main() {
|
|||
wasm_bindgen_futures::spawn_local(WebsysRenderer::start(CustomA))
|
||||
}
|
||||
|
||||
fn CustomA(ctx: Context<()>) -> VNode {
|
||||
let (val, set_val) = use_state(&ctx, || "abcdef".to_string() as String);
|
||||
fn CustomA(cx: Context<()>) -> VNode {
|
||||
let (val, set_val) = use_state(&cx, || "abcdef".to_string() as String);
|
||||
|
||||
ctx.render(rsx! {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
class: "m-8"
|
||||
"CustomA {val}"
|
||||
|
@ -42,12 +42,12 @@ mod components {
|
|||
val: String,
|
||||
}
|
||||
|
||||
pub fn CustomB(ctx: Context<PropsB>) -> VNode {
|
||||
let (first, last) = ctx.val.split_at(3);
|
||||
ctx.render(rsx! {
|
||||
pub fn CustomB(cx: Context<PropsB>) -> VNode {
|
||||
let (first, last) = cx.val.split_at(3);
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
class: "m-8"
|
||||
"CustomB {ctx.val}"
|
||||
"CustomB {cx.val}"
|
||||
CustomC {
|
||||
val: first.to_string()
|
||||
}
|
||||
|
@ -63,11 +63,11 @@ mod components {
|
|||
val: String,
|
||||
}
|
||||
|
||||
fn CustomC(ctx: Context<PropsC>) -> VNode {
|
||||
ctx.render(rsx! {
|
||||
fn CustomC(cx: Context<PropsC>) -> VNode {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
class: "m-8"
|
||||
"CustomC {ctx.val}"
|
||||
"CustomC {cx.val}"
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -7,8 +7,8 @@ fn main() {
|
|||
wasm_bindgen_futures::spawn_local(WebsysRenderer::start(App))
|
||||
}
|
||||
|
||||
fn App(ctx: Context<()>) -> VNode {
|
||||
ctx.render(rsx! {
|
||||
fn App(cx: Context<()>) -> VNode {
|
||||
cx.render(rsx! {
|
||||
main { class: "dark:bg-gray-800 bg-white relative h-screen"
|
||||
NavBar {}
|
||||
{(0..10).map(|f| rsx!(Landing { key: "{f}" }))}
|
||||
|
@ -16,8 +16,8 @@ fn App(ctx: Context<()>) -> VNode {
|
|||
})
|
||||
}
|
||||
|
||||
fn NavBar(ctx: Context<()>) -> VNode {
|
||||
ctx.render(rsx!{
|
||||
fn NavBar(cx: Context<()>) -> VNode {
|
||||
cx.render(rsx!{
|
||||
header { class: "h-24 sm:h-32 flex items-center z-30 w-full"
|
||||
div { class: "container mx-auto px-6 flex items-center justify-between"
|
||||
div { class: "uppercase text-gray-800 dark:text-white font-black text-3xl"
|
||||
|
@ -56,8 +56,8 @@ fn NavBar(ctx: Context<()>) -> VNode {
|
|||
})
|
||||
}
|
||||
|
||||
fn Landing(ctx: Context<()>) -> VNode {
|
||||
ctx.render(rsx!{
|
||||
fn Landing(cx: Context<()>) -> VNode {
|
||||
cx.render(rsx!{
|
||||
div { class: "bg-white dark:bg-gray-800 flex relative z-20 items-center"
|
||||
div { class: "container mx-auto px-6 flex flex-col justify-between items-center relative py-8"
|
||||
div { class: "flex flex-col"
|
||||
|
|
|
@ -8,9 +8,9 @@ fn main() {
|
|||
wasm_bindgen_futures::spawn_local(WebsysRenderer::start(App));
|
||||
}
|
||||
|
||||
fn App(ctx: Context<()>) -> VNode {
|
||||
let cansee = use_state_new(&ctx, || false);
|
||||
rsx! { in ctx,
|
||||
fn App(cx: Context<()>) -> VNode {
|
||||
let cansee = use_state_new(&cx, || false);
|
||||
rsx! { in cx,
|
||||
div {
|
||||
"Shadow of the child:"
|
||||
button { onclick: move |_| cansee.set(!**cansee)
|
||||
|
@ -21,8 +21,8 @@ fn App(ctx: Context<()>) -> VNode {
|
|||
}
|
||||
}
|
||||
|
||||
fn Child(ctx: Context<()>) -> VNode {
|
||||
rsx! { in ctx,
|
||||
fn Child(cx: Context<()>) -> VNode {
|
||||
rsx! { in cx,
|
||||
section { class: "py-6 bg-coolGray-100 text-coolGray-900"
|
||||
div { class: "container mx-auto flex flex-col items-center justify-center p-4 space-y-8 md:p-10 md:px-24 xl:px-48"
|
||||
h1 { class: "text-5xl font-bold leading-none text-center",
|
||||
|
|
|
@ -12,8 +12,8 @@ fn main() {
|
|||
wasm_bindgen_futures::spawn_local(WebsysRenderer::start(App));
|
||||
}
|
||||
|
||||
static App: FC<()> = |ctx| {
|
||||
ctx.render(rsx! {
|
||||
static App: FC<()> = |cx| {
|
||||
cx.render(rsx! {
|
||||
h2 { "abc 1" }
|
||||
div {
|
||||
"hello world!"
|
||||
|
|
|
@ -10,9 +10,9 @@ fn main() {
|
|||
wasm_bindgen_futures::spawn_local(WebsysRenderer::start(Example));
|
||||
}
|
||||
|
||||
static Example: FC<()> = |ctx| {
|
||||
static Example: FC<()> = |cx| {
|
||||
let nodes = (0..15).map(|f| rsx! (li { key: "{f}", "{f}"}));
|
||||
ctx.render(rsx! {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
span {
|
||||
class: "px-2 py-1 flex w-36 mt-4 items-center text-xs rounded-md font-semibold text-yellow-500 bg-yellow-100"
|
||||
|
|
|
@ -5,8 +5,8 @@ fn main() {
|
|||
wasm_bindgen_futures::spawn_local(dioxus_web::WebsysRenderer::start(App))
|
||||
}
|
||||
|
||||
fn App(ctx: Context<()>) -> VNode {
|
||||
ctx.render(rsx! {
|
||||
fn App(cx: Context<()>) -> VNode {
|
||||
cx.render(rsx! {
|
||||
div { "Hello, world!" }
|
||||
})
|
||||
}
|
||||
|
|
|
@ -12,8 +12,8 @@ fn main() {
|
|||
}
|
||||
|
||||
// this is a component
|
||||
static Example: FC<()> = |ctx| {
|
||||
let (event, set_event) = use_state(&ctx, || None);
|
||||
static Example: FC<()> = |cx| {
|
||||
let (event, set_event) = use_state(&cx, || None);
|
||||
|
||||
let handler = move |evt| {
|
||||
set_event(Some(evt));
|
||||
|
@ -21,7 +21,7 @@ static Example: FC<()> = |ctx| {
|
|||
|
||||
log::info!("hello world");
|
||||
|
||||
ctx.render(rsx! {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
|
||||
class: "py-12 px-4 w-full max-w-2xl mx-auto bg-red-100"
|
||||
|
@ -48,10 +48,10 @@ struct ExampleProps {
|
|||
name: String,
|
||||
}
|
||||
|
||||
static Example2: FC<ExampleProps> = |ctx| {
|
||||
ctx.render(rsx! {
|
||||
static Example2: FC<ExampleProps> = |cx| {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
h1 {"hello {ctx.name}"}
|
||||
h1 {"hello {cx.name}"}
|
||||
}
|
||||
})
|
||||
};
|
||||
|
|
|
@ -10,10 +10,10 @@ fn main() {
|
|||
wasm_bindgen_futures::spawn_local(WebsysRenderer::start(App));
|
||||
}
|
||||
|
||||
static App: FC<()> = |ctx| {
|
||||
let (val, set_val) = use_state(&ctx, || "asd".to_string());
|
||||
static App: FC<()> = |cx| {
|
||||
let (val, set_val) = use_state(&cx, || "asd".to_string());
|
||||
|
||||
ctx.render(rsx! {
|
||||
cx.render(rsx! {
|
||||
div { class: "max-w-lg max-w-xs bg-blue-800 shadow-2xl rounded-lg mx-auto text-center py-12 mt-4 rounded-xl"
|
||||
div { class: "container py-5 max-w-md mx-auto"
|
||||
h1 { class: "text-gray-200 text-center font-extrabold -mt-3 text-3xl",
|
||||
|
@ -35,8 +35,8 @@ static App: FC<()> = |ctx| {
|
|||
})
|
||||
};
|
||||
|
||||
static Example: FC<()> = |ctx| {
|
||||
ctx.render(rsx! {
|
||||
static Example: FC<()> = |cx| {
|
||||
cx.render(rsx! {
|
||||
div { class: "max-w-lg max-w-xs bg-blue-800 shadow-2xl rounded-lg mx-auto text-center py-12 mt-4 rounded-xl"
|
||||
div { class: "container py-5 max-w-md mx-auto"
|
||||
h1 { class: "text-gray-200 text-center font-extrabold -mt-3 text-3xl",
|
||||
|
@ -48,10 +48,10 @@ static Example: FC<()> = |ctx| {
|
|||
})
|
||||
};
|
||||
|
||||
static UserInput: FC<()> = |ctx| {
|
||||
let (val, set_val) = use_state(&ctx, || "asd".to_string());
|
||||
static UserInput: FC<()> = |cx| {
|
||||
let (val, set_val) = use_state(&cx, || "asd".to_string());
|
||||
|
||||
rsx! { in ctx,
|
||||
rsx! { in cx,
|
||||
div { class: "mb-4"
|
||||
input { class: "shadow appearance-none rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
|
||||
placeholder: "Username"
|
||||
|
|
|
@ -9,12 +9,12 @@ fn main() {
|
|||
wasm_bindgen_futures::spawn_local(WebsysRenderer::start(Example))
|
||||
}
|
||||
|
||||
static Example: FC<()> = |ctx| {
|
||||
let (name, set_name) = use_state(&ctx, || "...?");
|
||||
static Example: FC<()> = |cx| {
|
||||
let (name, set_name) = use_state(&cx, || "...?");
|
||||
|
||||
log::debug!("Running component....");
|
||||
|
||||
ctx.render(html! {
|
||||
cx.render(html! {
|
||||
<div>
|
||||
<section class="py-12 px-4 text-center">
|
||||
<div class="w-full max-w-2xl mx-auto">
|
||||
|
|
|
@ -12,10 +12,10 @@ fn main() {
|
|||
wasm_bindgen_futures::spawn_local(WebsysRenderer::start(App));
|
||||
}
|
||||
|
||||
static App: FC<()> = |ctx| {
|
||||
let (contents, set_contents) = use_state(&ctx, || "asd");
|
||||
static App: FC<()> = |cx| {
|
||||
let (contents, set_contents) = use_state(&cx, || "asd");
|
||||
|
||||
ctx.render(rsx! {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
class: "flex items-center justify-center flex-col"
|
||||
div {
|
||||
|
|
|
@ -13,10 +13,10 @@ fn main() {
|
|||
wasm_bindgen_futures::spawn_local(WebsysRenderer::start(App));
|
||||
}
|
||||
|
||||
static App: FC<()> = |ctx| {
|
||||
let (contents, set_contents) = use_state(&ctx, || "asd");
|
||||
static App: FC<()> = |cx| {
|
||||
let (contents, set_contents) = use_state(&cx, || "asd");
|
||||
|
||||
ctx.render(rsx! {
|
||||
cx.render(rsx! {
|
||||
div { class: "flex items-center justify-center flex-col"
|
||||
div { class: "flex items-center justify-center"
|
||||
div { class: "flex flex-col bg-white rounded p-4 w-full max-w-xs"
|
||||
|
|
|
@ -25,11 +25,11 @@ pub struct TodoItem {
|
|||
pub contents: String,
|
||||
}
|
||||
|
||||
static App: FC<()> = |ctx| {
|
||||
let (draft, set_draft) = use_state(&ctx, || "".to_string());
|
||||
let (filter, set_filter) = use_state(&ctx, || FilterState::All);
|
||||
let todos = use_state_new(&ctx, || BTreeMap::<uuid::Uuid, TodoItem>::new());
|
||||
ctx.render(rsx!(
|
||||
static App: FC<()> = |cx| {
|
||||
let (draft, set_draft) = use_state(&cx, || "".to_string());
|
||||
let (filter, set_filter) = use_state(&cx, || FilterState::All);
|
||||
let todos = use_state_new(&cx, || BTreeMap::<uuid::Uuid, TodoItem>::new());
|
||||
cx.render(rsx!(
|
||||
div {
|
||||
id: "app"
|
||||
div {
|
||||
|
@ -131,9 +131,9 @@ static App: FC<()> = |ctx| {
|
|||
))
|
||||
};
|
||||
|
||||
pub fn FilterToggles(ctx: Context<()>) -> VNode {
|
||||
// let reducer = recoil::use_callback(&ctx, || ());
|
||||
// let items_left = recoil::use_atom_family(&ctx, &TODOS, uuid::Uuid::new_v4());
|
||||
pub fn FilterToggles(cx: Context<()>) -> VNode {
|
||||
// let reducer = recoil::use_callback(&cx, || ());
|
||||
// let items_left = recoil::use_atom_family(&cx, &TODOS, uuid::Uuid::new_v4());
|
||||
|
||||
let toggles = [
|
||||
("All", "", FilterState::All),
|
||||
|
@ -158,7 +158,7 @@ pub fn FilterToggles(ctx: Context<()>) -> VNode {
|
|||
let item_text = "";
|
||||
let items_left = "";
|
||||
|
||||
ctx.render(rsx! {
|
||||
cx.render(rsx! {
|
||||
footer {
|
||||
span {
|
||||
strong {"{items_left}"}
|
||||
|
|
|
@ -10,8 +10,8 @@ fn main() {
|
|||
wasm_bindgen_futures::spawn_local(WebsysRenderer::start(Example));
|
||||
}
|
||||
|
||||
static Example: FC<()> = |ctx| {
|
||||
ctx.render(rsx! {
|
||||
static Example: FC<()> = |cx| {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
span {
|
||||
class: "px-2 py-1 flex w-36 mt-4 items-center text-xs rounded-md font-semibold text-yellow-500 bg-yellow-100"
|
||||
|
|
|
@ -5,10 +5,10 @@
|
|||
// wasm_bindgen_futures::spawn_local(WebsysRenderer::start(Example));
|
||||
// }
|
||||
|
||||
// fn Example(ctx: Context, props: ()) -> VNode {
|
||||
// let user_data = use_sql_query(&ctx, USER_DATA_QUERY);
|
||||
// fn Example(cx: Context, props: ()) -> VNode {
|
||||
// let user_data = use_sql_query(&cx, USER_DATA_QUERY);
|
||||
|
||||
// ctx.render(rsx! {
|
||||
// cx.render(rsx! {
|
||||
// h1 { "Hello, {username}"}
|
||||
// button {
|
||||
// "Delete user"
|
||||
|
|
|
@ -25,10 +25,10 @@ struct ExampleProps {
|
|||
initial_name: &'static str,
|
||||
}
|
||||
|
||||
static Example: FC<ExampleProps> = |ctx| {
|
||||
let name = use_state_new(&ctx, move || ctx.initial_name);
|
||||
static Example: FC<ExampleProps> = |cx| {
|
||||
let name = use_state_new(&cx, move || cx.initial_name);
|
||||
|
||||
ctx.render(rsx! {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
class: "py-12 px-4 text-center w-full max-w-2xl mx-auto"
|
||||
span {
|
||||
|
@ -55,12 +55,12 @@ struct ButtonProps<'src, F: Fn(Rc<dyn MouseEvent>)> {
|
|||
handler: F,
|
||||
}
|
||||
|
||||
fn CustomButton<'a, F: Fn(MouseEvent)>(ctx: Context<'a, ButtonProps<'a, F>>) -> VNode {
|
||||
ctx.render(rsx!{
|
||||
fn CustomButton<'a, F: Fn(MouseEvent)>(cx: Context<'a, ButtonProps<'a, F>>) -> VNode {
|
||||
cx.render(rsx!{
|
||||
button {
|
||||
class: "inline-block py-4 px-8 mr-6 leading-none text-white bg-indigo-600 hover:bg-indigo-900 font-semibold rounded shadow"
|
||||
onmouseover: {&ctx.handler}
|
||||
"{ctx.name}"
|
||||
onmouseover: {&cx.handler}
|
||||
"{cx.name}"
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -75,10 +75,10 @@ impl<F: Fn(MouseEvent)> PartialEq for ButtonProps<'_, F> {
|
|||
struct PlaceholderProps {
|
||||
val: &'static str,
|
||||
}
|
||||
fn Placeholder(ctx: Context<PlaceholderProps>) -> VNode {
|
||||
ctx.render(rsx! {
|
||||
fn Placeholder(cx: Context<PlaceholderProps>) -> VNode {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
"child: {ctx.val}"
|
||||
"child: {cx.val}"
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -2,9 +2,9 @@ use crate::recoil;
|
|||
use crate::state::{FilterState, TODOS};
|
||||
use dioxus_core::prelude::*;
|
||||
|
||||
pub fn FilterToggles(ctx: Context<()>) -> VNode {
|
||||
let reducer = recoil::use_callback(&ctx, || ());
|
||||
let items_left = recoil::use_atom_family(&ctx, &TODOS, uuid::Uuid::new_v4());
|
||||
pub fn FilterToggles(cx: Context<()>) -> VNode {
|
||||
let reducer = recoil::use_callback(&cx, || ());
|
||||
let items_left = recoil::use_atom_family(&cx, &TODOS, uuid::Uuid::new_v4());
|
||||
|
||||
let toggles = [
|
||||
("All", "", FilterState::All),
|
||||
|
@ -27,7 +27,7 @@ pub fn FilterToggles(ctx: Context<()>) -> VNode {
|
|||
let item_text = "";
|
||||
let items_left = "";
|
||||
|
||||
ctx.render(rsx! {
|
||||
cx.render(rsx! {
|
||||
footer {
|
||||
span {
|
||||
strong {"{items_left}"}
|
||||
|
|
|
@ -10,8 +10,8 @@ use dioxus_web::{prelude::*, WebsysRenderer};
|
|||
static APP_STYLE: &'static str = include_str!("./style.css");
|
||||
|
||||
fn main() {
|
||||
wasm_bindgen_futures::spawn_local(WebsysRenderer::start(|ctx| {
|
||||
ctx.render(rsx! {
|
||||
wasm_bindgen_futures::spawn_local(WebsysRenderer::start(|cx| {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
id: "app"
|
||||
// style { "{APP_STYLE}" }
|
||||
|
|
|
@ -33,10 +33,10 @@ impl RecoilContext<()> {
|
|||
// let (set, get) = (self.set, self.get);
|
||||
|
||||
// TOODS
|
||||
// .get(&ctx)
|
||||
// .get(&cx)
|
||||
// .iter()
|
||||
// .filter(|(k, v)| v.checked)
|
||||
// .map(|(k, v)| TODOS.remove(&ctx, k));
|
||||
// .map(|(k, v)| TODOS.remove(&cx, k));
|
||||
}
|
||||
|
||||
pub fn set_filter(&self, filter: &FilterState) {}
|
||||
|
|
|
@ -7,11 +7,11 @@ pub struct TodoEntryProps {
|
|||
id: uuid::Uuid,
|
||||
}
|
||||
|
||||
pub fn TodoEntry(ctx: Context, props: &TodoEntryProps) -> VNode {
|
||||
let (is_editing, set_is_editing) = use_state(&ctx, || false);
|
||||
let todo = use_atom_family(&ctx, &TODOS, ctx.id);
|
||||
pub fn TodoEntry(cx: Context, props: &TodoEntryProps) -> VNode {
|
||||
let (is_editing, set_is_editing) = use_state(&cx, || false);
|
||||
let todo = use_atom_family(&cx, &TODOS, cx.id);
|
||||
|
||||
ctx.render(rsx! (
|
||||
cx.render(rsx! (
|
||||
li {
|
||||
"{todo.id}"
|
||||
input {
|
||||
|
|
|
@ -6,12 +6,12 @@ use crate::{
|
|||
};
|
||||
use dioxus_core::prelude::*;
|
||||
|
||||
pub fn TodoList(ctx: Context<()>) -> VNode {
|
||||
let (draft, set_draft) = use_state(&ctx, || "".to_string());
|
||||
let (todos, _) = use_state(&ctx, || Vec::<TodoItem>::new());
|
||||
let filter = use_atom(&ctx, &FILTER);
|
||||
pub fn TodoList(cx: Context<()>) -> VNode {
|
||||
let (draft, set_draft) = use_state(&cx, || "".to_string());
|
||||
let (todos, _) = use_state(&cx, || Vec::<TodoItem>::new());
|
||||
let filter = use_atom(&cx, &FILTER);
|
||||
|
||||
ctx.render(rsx! {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
header {
|
||||
class: "header"
|
||||
|
|
|
@ -27,8 +27,8 @@ pub struct TodoItem {
|
|||
// =======================
|
||||
// Components
|
||||
// =======================
|
||||
pub fn App(ctx: Context<()>) -> VNode {
|
||||
ctx.render(rsx! {
|
||||
pub fn App(cx: Context<()>) -> VNode {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
id: "app"
|
||||
|
||||
|
@ -52,12 +52,12 @@ pub fn App(ctx: Context<()>) -> VNode {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn TodoList(ctx: Context<()>) -> VNode {
|
||||
let (draft, set_draft) = use_state(&ctx, || "".to_string());
|
||||
let (todos, set_todos) = use_state(&ctx, || HashMap::<uuid::Uuid, Rc<TodoItem>>::new());
|
||||
let (filter, set_filter) = use_state(&ctx, || FilterState::All);
|
||||
pub fn TodoList(cx: Context<()>) -> VNode {
|
||||
let (draft, set_draft) = use_state(&cx, || "".to_string());
|
||||
let (todos, set_todos) = use_state(&cx, || HashMap::<uuid::Uuid, Rc<TodoItem>>::new());
|
||||
let (filter, set_filter) = use_state(&cx, || FilterState::All);
|
||||
|
||||
ctx.render(rsx! {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
header {
|
||||
class: "header"
|
||||
|
@ -101,8 +101,8 @@ pub struct TodoEntryProps {
|
|||
item: Rc<TodoItem>,
|
||||
}
|
||||
|
||||
pub fn TodoEntry(ctx: Context<TodoEntryProps>) -> VNode {
|
||||
let (is_editing, set_is_editing) = use_state(&ctx, || false);
|
||||
pub fn TodoEntry(cx: Context<TodoEntryProps>) -> VNode {
|
||||
let (is_editing, set_is_editing) = use_state(&cx, || false);
|
||||
let contents = "";
|
||||
let todo = TodoItem {
|
||||
checked: false,
|
||||
|
@ -110,7 +110,7 @@ pub fn TodoEntry(ctx: Context<TodoEntryProps>) -> VNode {
|
|||
id: uuid::Uuid::new_v4(),
|
||||
};
|
||||
|
||||
ctx.render(rsx! (
|
||||
cx.render(rsx! (
|
||||
li {
|
||||
"{todo.id}"
|
||||
input {
|
||||
|
@ -127,7 +127,7 @@ pub fn TodoEntry(ctx: Context<TodoEntryProps>) -> VNode {
|
|||
))
|
||||
}
|
||||
|
||||
pub fn FilterToggles(ctx: Context<()>) -> VNode {
|
||||
pub fn FilterToggles(cx: Context<()>) -> VNode {
|
||||
let toggles = [
|
||||
("All", "", FilterState::All),
|
||||
("Active", "active", FilterState::Active),
|
||||
|
@ -151,7 +151,7 @@ pub fn FilterToggles(ctx: Context<()>) -> VNode {
|
|||
let item_text = "";
|
||||
let items_left = "";
|
||||
|
||||
ctx.render(rsx! {
|
||||
cx.render(rsx! {
|
||||
footer {
|
||||
span {
|
||||
strong {"{items_left}"}
|
||||
|
|
|
@ -72,10 +72,10 @@ impl TodoManager {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn TodoList(ctx: Context<()>) -> VNode {
|
||||
let draft = use_state_new(&ctx, || "".to_string());
|
||||
let todos = use_read(&ctx, &TODO_LIST);
|
||||
let filter = use_read(&ctx, &FILTER);
|
||||
pub fn TodoList(cx: Context<()>) -> VNode {
|
||||
let draft = use_state_new(&cx, || "".to_string());
|
||||
let todos = use_read(&cx, &TODO_LIST);
|
||||
let filter = use_read(&cx, &FILTER);
|
||||
|
||||
let todolist = todos
|
||||
.values()
|
||||
|
@ -91,7 +91,7 @@ pub fn TodoList(ctx: Context<()>) -> VNode {
|
|||
})
|
||||
});
|
||||
|
||||
rsx! { in ctx,
|
||||
rsx! { in cx,
|
||||
div {
|
||||
header {
|
||||
class: "header"
|
||||
|
@ -116,11 +116,11 @@ pub struct TodoEntryProps {
|
|||
id: Uuid,
|
||||
}
|
||||
|
||||
pub fn TodoEntry(ctx: Context, props: &TodoEntryProps) -> VNode {
|
||||
let (is_editing, set_is_editing) = use_state(&ctx, || false);
|
||||
let todo = use_read(&ctx, &TODO_LIST).get(&ctx.id).unwrap();
|
||||
pub fn TodoEntry(cx: Context, props: &TodoEntryProps) -> VNode {
|
||||
let (is_editing, set_is_editing) = use_state(&cx, || false);
|
||||
let todo = use_read(&cx, &TODO_LIST).get(&cx.id).unwrap();
|
||||
|
||||
ctx.render(rsx! (
|
||||
cx.render(rsx! (
|
||||
li {
|
||||
"{todo.id}"
|
||||
input {
|
||||
|
@ -137,9 +137,9 @@ pub fn TodoEntry(ctx: Context, props: &TodoEntryProps) -> VNode {
|
|||
))
|
||||
}
|
||||
|
||||
pub fn FilterToggles(ctx: Context<()>) -> VNode {
|
||||
let reducer = TodoManager(use_recoil_api(ctx));
|
||||
let items_left = use_read(ctx, &TODOS_LEFT);
|
||||
pub fn FilterToggles(cx: Context<()>) -> VNode {
|
||||
let reducer = TodoManager(use_recoil_api(cx));
|
||||
let items_left = use_read(cx, &TODOS_LEFT);
|
||||
|
||||
let toggles = [
|
||||
("All", "", FilterState::All),
|
||||
|
@ -164,7 +164,7 @@ pub fn FilterToggles(ctx: Context<()>) -> VNode {
|
|||
_ => "items",
|
||||
};
|
||||
|
||||
rsx! { in ctx,
|
||||
rsx! { in cx,
|
||||
footer {
|
||||
span {
|
||||
strong {"{items_left}"}
|
||||
|
@ -178,8 +178,8 @@ pub fn FilterToggles(ctx: Context<()>) -> VNode {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn Footer(ctx: Context<()>) -> VNode {
|
||||
rsx! { in ctx,
|
||||
pub fn Footer(cx: Context<()>) -> VNode {
|
||||
rsx! { in cx,
|
||||
footer { class: "info"
|
||||
p {"Double-click to edit a todo"}
|
||||
p {
|
||||
|
@ -196,9 +196,9 @@ pub fn Footer(ctx: Context<()>) -> VNode {
|
|||
|
||||
const APP_STYLE: &'static str = include_str!("./todomvc/style.css");
|
||||
|
||||
fn App(ctx: Context<()>) -> VNode {
|
||||
use_init_recoil_root(ctx, |_| {});
|
||||
rsx! { in ctx,
|
||||
fn App(cx: Context<()>) -> VNode {
|
||||
use_init_recoil_root(cx, |_| {});
|
||||
rsx! { in cx,
|
||||
div { id: "app"
|
||||
TodoList {}
|
||||
Footer {}
|
||||
|
|
|
@ -9,8 +9,8 @@ fn main() {
|
|||
wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
|
||||
console_error_panic_hook::set_once();
|
||||
|
||||
wasm_bindgen_futures::spawn_local(WebsysRenderer::start(|ctx| {
|
||||
ctx.render(html! {
|
||||
wasm_bindgen_futures::spawn_local(WebsysRenderer::start(|cx| {
|
||||
cx.render(html! {
|
||||
<div>
|
||||
<div class="flex items-center justify-center flex-col">
|
||||
<div class="flex items-center justify-center">
|
||||
|
|
|
@ -179,9 +179,9 @@ mod tests {
|
|||
pretty_env_logger::init();
|
||||
log::info!("Hello!");
|
||||
|
||||
wasm_bindgen_futures::spawn_local(WebsysRenderer::start(|ctx| {
|
||||
wasm_bindgen_futures::spawn_local(WebsysRenderer::start(|cx| {
|
||||
todo!()
|
||||
// ctx.render(html! {
|
||||
// cx.render(html! {
|
||||
// <div>
|
||||
// "Hello world"
|
||||
// <button onclick={move |_| log::info!("button1 clicked!")}> "click me" </button>
|
||||
|
|
|
@ -147,10 +147,10 @@ fn main() {
|
|||
wasm_bindgen_futures::spawn_local(WebsysRenderer::start(Example));
|
||||
}
|
||||
|
||||
fn Component(ctx: Context, props: ()) -> VNode {
|
||||
let user_data = use_sql_query(&ctx, USER_DATA_QUERY);
|
||||
fn Component(cx: Context, props: ()) -> VNode {
|
||||
let user_data = use_sql_query(&cx, USER_DATA_QUERY);
|
||||
|
||||
ctx.render(rsx! {
|
||||
cx.render(rsx! {
|
||||
h1 { "Hello, {username}"}
|
||||
button {
|
||||
"Delete user"
|
||||
|
|
|
@ -8,8 +8,8 @@ Dioxus-webview is an attempt at making a simpler "Tauri" where creating desktop
|
|||
// main.rs
|
||||
#[async_std::main]
|
||||
async fn main() {
|
||||
dioxus_webview::new(|ctx| {
|
||||
let (count, set_count) = use_state(&ctx, || 0);
|
||||
dioxus_webview::new(|cx| {
|
||||
let (count, set_count) = use_state(&cx, || 0);
|
||||
html! {
|
||||
<div>
|
||||
<h1> "Dioxus Desktop Demo" </h1>
|
||||
|
|
|
@ -36,22 +36,22 @@ fn blah() {
|
|||
let handler = dioxus_liveview::new_handler()
|
||||
.from_directory("abc123") // serve a given directory as the root
|
||||
.with_context(|| SomeContext {}) // build out a new context for all of the server-rendered components to share
|
||||
.with_route(SERVER_RENDERED_KEY, |ctx: &ServerRendered| {
|
||||
.with_route(SERVER_RENDERED_KEY, |cx: &ServerRendered| {
|
||||
//
|
||||
})
|
||||
.with_route(SERVER_RENDERED_KEY, |ctx| {
|
||||
.with_route(SERVER_RENDERED_KEY, |cx| {
|
||||
//
|
||||
})
|
||||
.with_route(SERVER_RENDERED_KEY, |ctx| {
|
||||
.with_route(SERVER_RENDERED_KEY, |cx| {
|
||||
//
|
||||
})
|
||||
.with_route(SERVER_RENDERED_KEY, |ctx| {
|
||||
.with_route(SERVER_RENDERED_KEY, |cx| {
|
||||
//
|
||||
})
|
||||
.with_route(SERVER_RENDERED_KEY, |ctx| {
|
||||
.with_route(SERVER_RENDERED_KEY, |cx| {
|
||||
//
|
||||
})
|
||||
.with_route(SERVER_RENDERED_KEY, |ctx| {
|
||||
.with_route(SERVER_RENDERED_KEY, |cx| {
|
||||
//
|
||||
})
|
||||
// depend on the framework, build a different type of handler
|
||||
|
|
|
@ -17,8 +17,8 @@ fn main() {
|
|||
.expect("Webview finished");
|
||||
}
|
||||
|
||||
static Example: FC<()> = |ctx| {
|
||||
ctx.render(html! {
|
||||
static Example: FC<()> = |cx| {
|
||||
cx.render(html! {
|
||||
<div>
|
||||
<svg class="octicon octicon-star v-align-text-bottom"
|
||||
viewBox="0 0 14 16" version="1.1"
|
||||
|
@ -36,8 +36,8 @@ static Example: FC<()> = |ctx| {
|
|||
</div>
|
||||
})
|
||||
};
|
||||
// static Example: FC<()> = |ctx| {
|
||||
// ctx.render(rsx! {
|
||||
// static Example: FC<()> = |cx| {
|
||||
// cx.render(rsx! {
|
||||
// div {
|
||||
// class: "flex items-center justify-center flex-col"
|
||||
// div {
|
||||
|
|
28
src/lib.rs
28
src/lib.rs
|
@ -32,7 +32,7 @@
|
|||
//! ```
|
||||
//! use dioxus::prelude::*;
|
||||
//!
|
||||
//! fn Example(ctx: Context<()>) -> VNode {
|
||||
//! fn Example(cx: Context<()>) -> VNode {
|
||||
//! html! { <div> "Hello, world!" </div> }
|
||||
//! }
|
||||
//! ```
|
||||
|
@ -44,8 +44,8 @@
|
|||
//! #[derive(Props)]
|
||||
//! struct Props { name: String }
|
||||
//!
|
||||
//! fn Example(ctx: Context<Props>) -> VNode {
|
||||
//! html! { <div> "Hello {ctx.props.name}!" </div> }
|
||||
//! fn Example(cx: Context<Props>) -> VNode {
|
||||
//! html! { <div> "Hello {cx.props.name}!" </div> }
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
|
@ -59,8 +59,8 @@
|
|||
//! #[derive(Props)]
|
||||
//! struct Props<'a> { name: &'a str }
|
||||
//!
|
||||
//! fn Example<'a>(ctx: Context<'a, Props<'a>>) -> VNode {
|
||||
//! html! { <div> "Hello {ctx.props.name}!" </div> }
|
||||
//! fn Example<'a>(cx: Context<'a, Props<'a>>) -> VNode {
|
||||
//! html! { <div> "Hello {cx.props.name}!" </div> }
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
|
@ -74,8 +74,8 @@
|
|||
//! #[derive(Props)]
|
||||
//! struct Props { name: String }
|
||||
//!
|
||||
//! static Example: FC<Props> = |ctx| {
|
||||
//! html! { <div> "Hello {ctx.props.name}!" </div> }
|
||||
//! static Example: FC<Props> = |cx| {
|
||||
//! html! { <div> "Hello {cx.props.name}!" </div> }
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
|
@ -102,9 +102,9 @@
|
|||
//! Dioxus uses hooks for state management. Hooks are a form of state persisted between calls of the function component.
|
||||
//!
|
||||
//! ```
|
||||
//! static Example: FC<()> = |ctx| {
|
||||
//! let (val, set_val) = use_state(&ctx, || 0);
|
||||
//! ctx.render(rsx!(
|
||||
//! static Example: FC<()> = |cx| {
|
||||
//! let (val, set_val) = use_state(&cx, || 0);
|
||||
//! cx.render(rsx!(
|
||||
//! button { onclick: move |_| set_val(val + 1) }
|
||||
//! ))
|
||||
//! }
|
||||
|
@ -114,8 +114,8 @@
|
|||
//! which allows the persistence of data between function component renders. This primitive is exposed directly through
|
||||
//! the `Context` item:
|
||||
//! ```
|
||||
//! fn my_hook<'a>(ctx: &impl Scoped<'a>) -> &'a String {
|
||||
//! ctx.use_hook(
|
||||
//! fn my_hook<'a>(cx: &impl Scoped<'a>) -> &'a String {
|
||||
//! cx.use_hook(
|
||||
//! // Initializer stores a value
|
||||
//! || String::new("stored_data"),
|
||||
//!
|
||||
|
@ -170,8 +170,8 @@
|
|||
//! diouxs::web::launch(Example);
|
||||
//! }
|
||||
//!
|
||||
//! static Example: FC<()> = |ctx| {
|
||||
//! ctx.render(rsx! {
|
||||
//! static Example: FC<()> = |cx| {
|
||||
//! cx.render(rsx! {
|
||||
//! div { "Hello World!" }
|
||||
//! })
|
||||
//! };
|
||||
|
|
Loading…
Reference in a new issue