chore: rename ctx to cx

This commit is contained in:
Jonathan Kelley 2021-06-25 21:15:33 -04:00
parent 23c14078bb
commit 81382e7044
99 changed files with 789 additions and 664 deletions

View file

@ -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]

View file

@ -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!" } ))
}
```

View file

@ -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())
}}

View file

@ -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.

View file

@ -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> },

View file

@ -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.

View file

@ -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>
})
}
```

View file

@ -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>

View file

@ -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())
}}

View file

@ -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>
}
}
```

View file

@ -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
}
```

View file

@ -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 {
```

View file

@ -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>
}
```

View file

@ -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.

View file

@ -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)
}

View file

@ -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}!"}

View file

@ -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
View 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)
}

View file

@ -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,

View file

@ -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" }
))

View file

@ -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}"

View file

@ -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" }

View file

@ -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" }

View file

@ -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}" }

View file

@ -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}" }

View file

@ -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 {}

View file

@ -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" }

View file

@ -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) }

View file

@ -2,7 +2,7 @@ fn main() {}
use dioxus_core::prelude::*;
static App: FC<()> = |ctx| {
static App: FC<()> = |cx| {
//
use_initialize_app()
};

View file

@ -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}

View file

@ -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!{

View file

@ -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)
}
}
}

View file

@ -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
// }

View file

@ -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);

View file

@ -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]

View file

@ -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,

View file

@ -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))
});
}
}

View file

@ -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
)

View file

@ -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
})
}),

View file

@ -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
// })

View file

@ -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"]

View file

@ -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()
}))

View file

@ -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()
}))

View file

@ -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)} />

View file

@ -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

View file

@ -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())
}))
};

View file

@ -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);

View file

@ -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,

View file

@ -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 => {

View file

@ -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

View file

@ -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
});

View file

@ -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!()
}

View file

@ -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 {
}

View file

@ -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 {
}

View file

@ -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 {
}

View file

@ -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

View file

@ -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 {
}

View file

@ -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"

View file

@ -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 {

View file

@ -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();

View file

@ -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)) {

View file

@ -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| {
//

View file

@ -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 {
}

View file

@ -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 {
// }

View file

@ -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}

View file

@ -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")]

View file

@ -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!{

View file

@ -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!"} }) }
}

View file

@ -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()}
}
})
};

View file

@ -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}"

View file

@ -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}"
}
})
}

View file

@ -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"

View file

@ -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",

View file

@ -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!"

View file

@ -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"

View file

@ -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!" }
})
}

View file

@ -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}"}
}
})
};

View file

@ -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"

View file

@ -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">

View file

@ -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 {

View file

@ -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"

View file

@ -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}"}

View file

@ -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"

View file

@ -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"

View file

@ -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}"
}
})
}

View file

@ -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}"}

View file

@ -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}" }

View file

@ -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) {}

View file

@ -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 {

View file

@ -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"

View file

@ -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}"}

View file

@ -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 {}

View file

@ -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">

View file

@ -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>

View file

@ -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"

View file

@ -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>

View file

@ -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

View file

@ -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 {

View file

@ -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!" }
//! })
//! };