docs: update local examples and docs to support new syntaxes

This commit is contained in:
Jonathan Kelley 2021-12-15 15:56:53 -05:00
parent e495b09bf1
commit 4de16c4779
118 changed files with 520 additions and 1154 deletions

View file

@ -1,3 +1,7 @@
{
"rust-analyzer.cargo.allFeatures": true
"rust-analyzer.cargo.allFeatures": true,
"rust-analyzer.cargo.features": [
"desktop",
"router"
],
}

View file

@ -49,7 +49,7 @@
Dioxus is a portable, performant, and ergonomic framework for building cross-platform user experiences in Rust.
```rust
fn App(cx: Scope<()>) -> Element {
fn app(cx: Scope<()>) -> Element {
let mut count = use_state(&cx, || 0);
cx.render(rsx!(
@ -76,23 +76,21 @@ If you know React, then you already know Dioxus.
<table style="width:100%" align="center">
<tr >
<th><a href="http://github.com/jkelleyrtp/dioxus">Web</a></th>
<th><a href="http://github.com/jkelleyrtp/dioxus">Desktop</a></th>
<th><a href="http://github.com/jkelleyrtp/dioxus">Mobile</a></th>
<th><a href="http://github.com/jkelleyrtp/dioxus">State</a></th>
<th><a href="http://github.com/jkelleyrtp/dioxus">Docs</a></th>
<th><a href="http://github.com/jkelleyrtp/dioxus">Tools</a></th>
<th><a href="https://dioxuslabs.com/book/">Web</a></th>
<th><a href="https://dioxuslabs.com/book/">Desktop</a></th>
<th><a href="https://dioxuslabs.com/book/">Mobile</a></th>
<th><a href="https://dioxuslabs.com/book/">State</a></th>
<th><a href="https://dioxuslabs.com/book/">Docs</a></th>
<th><a href="https://dioxuslabs.com/book/">Tools</a></th>
<tr>
</table>
## Examples:
| File Navigator (Desktop) | Bluetooth scanner (Desktop) | TodoMVC (All platforms) | Widget Gallery |
| File Navigator (Desktop) | Bluetooth scanner (Desktop) | TodoMVC (All platforms) | Tailwind (Liveview) |
| --------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| [![asd](https://github.com/DioxusLabs/file-explorer-example/raw/master/image.png)](https://github.com/DioxusLabs/file-explorer-example) | [![asd](https://github.com/DioxusLabs/file-explorer-example/raw/master/image.png)](https://github.com/DioxusLabs/file-explorer-example) | [![asd](https://github.com/DioxusLabs/todomvc/raw/master/example.png)](https://github.com/dioxusLabs/todomvc/) | [![asd](https://github.com/DioxusLabs/file-explorer-example/raw/master/image.png)](https://github.com/DioxusLabs/file-explorer-example) |
<!-- | ![asd](https://github.com/DioxusLabs/todomvc/blob/master/example.png) | [![asd](https://github.com/DioxusLabs/todomvc/blob/master/example.png)](https://github.com/dioxusLabs/todomvc/) | ![asd](https://sixtyfps.io/resources/printerdemo_screenshot.png) | -->
See the awesome-dioxus page for a curated list of content in the Dioxus Ecosystem.
@ -169,6 +167,7 @@ Dioxus is heavily inspired by React, but we want your transition to feel like an
| 1st class global state | ✅ | ✅ | redux/recoil/mobx on top of context |
| Runs natively | ✅ | ❓ | runs as a portable binary w/o a runtime (Node) |
| Subtree Memoization | ✅ | ❓ | skip diffing static element subtrees |
| High-efficiency templates | 🛠 | ❓ | rsx! calls are translated to templates on the DOM's side |
| Compile-time correct | ✅ | ❓ | Throw errors on invalid template layouts |
| Heuristic Engine | ✅ | ❓ | track component memory usage to minimize future allocations |
| Fine-grained reactivity | 👀 | ❓ | Skip diffing for fine-grain updates |

View file

@ -6,7 +6,7 @@
```rust
fn App(cx: Context, props: &()) -> Element {
let mut count = use_state(cx, || 0);
let mut count = use_state(&cx, || 0);
cx.render(rsx!(
h1 { "High-Five counter: {count}" }
@ -53,7 +53,7 @@ Dioxus supports server-side rendering!
For rendering statically to an `.html` file or from a WebServer, then you'll want to make sure the `ssr` feature is enabled in the `dioxus` crate and use the `dioxus::ssr` API. We don't expect the SSR API to change drastically in the future.
```rust
let contents = dioxus::ssr::render_vdom(&dom, |c| c);
let contents = dioxus::ssr::render_vdom(&dom);
```
[Jump to the getting started guide for SSR.]()

View file

@ -45,7 +45,7 @@ As the UI grows in scale, our logic to keep each element in the proper state wou
Instead, with Dioxus, we *declare* what we want our UI to look like:
```rust
let mut state = use_state(cx, || "red");
let mut state = use_state(&cx, || "red");
cx.render(rsx!(
Container {

View file

@ -21,9 +21,9 @@ fn test() -> DomTree {
}
}
static TestComponent: FC<()> = |cx, props|html!{<div>"Hello world"</div>};
static TestComponent: Component<()> = |cx, props|html!{<div>"Hello world"</div>};
static TestComponent: FC<()> = |cx, props|{
static TestComponent: Component<()> = |cx, props|{
let g = "BLAH";
html! {
<div> "Hello world" </div>
@ -31,7 +31,7 @@ static TestComponent: FC<()> = |cx, props|{
};
#[functional_component]
static TestComponent: FC<{ name: String }> = |cx, props|html! { <div> "Hello {name}" </div> };
static TestComponent: Component<{ name: String }> = |cx, props|html! { <div> "Hello {name}" </div> };
```
## Why this behavior?

View file

@ -12,7 +12,7 @@ Your component today might look something like this:
```rust
fn Comp(cx: Context<()>) -> DomTree {
let (title, set_title) = use_state(cx, || "Title".to_string());
let (title, set_title) = use_state(&cx, || "Title".to_string());
cx.render(rsx!{
input {
value: title,
@ -26,7 +26,7 @@ This component is fairly straightforward - the input updates its own value on ev
```rust
fn Comp(cx: Context<()>) -> DomTree {
let (title, set_title) = use_state(cx, || "Title".to_string());
let (title, set_title) = use_state(&cx, || "Title".to_string());
cx.render(rsx!{
div {
input {
@ -96,7 +96,7 @@ Sometimes you want a signal to propagate across your app, either through far-awa
```rust
const TITLE: Atom<String> = || "".to_string();
const Provider: FC<()> = |cx, props|{
const Provider: Component<()> = |cx, props|{
let title = use_signal(&cx, &TITLE);
rsx!(cx, input { value: title })
};
@ -105,7 +105,7 @@ const Provider: FC<()> = |cx, props|{
If we use the `TITLE` atom in another component, we can cause updates to flow between components without calling render or diffing either component trees:
```rust
const Receiver: FC<()> = |cx, props|{
const Receiver: Component<()> = |cx, props|{
let title = use_signal(&cx, &TITLE);
log::info!("This will only be called once!");
rsx!(cx,
@ -132,7 +132,7 @@ Dioxus automatically understands how to use your signals when mixed with iterato
```rust
const DICT: AtomFamily<String, String> = |_| {};
const List: FC<()> = |cx, props|{
const List: Component<()> = |cx, props|{
let dict = use_signal(&cx, &DICT);
cx.render(rsx!(
ul {

View file

@ -124,7 +124,7 @@ fn VoteButton(cx: Context, props: &VoteButtonProps) -> Element {
cx.render(rsx!{
div { class: "votebutton"
div { class: "arrow up" }
div { class: "score", "{props.score}"}
div { class: "score", "{cx.props.score}"}
div { class: "arrow down" }
}
})
@ -147,7 +147,7 @@ struct TitleCardProps<'a> {
fn TitleCard(cx: Context, props: &TitleCardProps) -> Element {
cx.render(rsx!{
h1 { "{props.title}" }
h1 { "{cx.props.title}" }
})
}
```

View file

@ -83,7 +83,7 @@ fn App(cx: Context, props: &())-> Element {
This syntax even enables us to write a one-line component:
```rust
static App: FC<()> = |cx, props| rsx!(cx, "hello world!");
static App: Component<()> = |cx, props| rsx!(cx, "hello world!");
```
Alternatively, for match statements, we can just return the builder itself and pass it into a final, single call to `cx.render`:

View file

@ -22,7 +22,7 @@ Let's say our app looks something like this:
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(App, |c| c);
dioxus::desktop::launch(App);
}
fn App((cx, props): Component<()>) -> Element {}
@ -87,7 +87,7 @@ In our `main.rs`, we'll want to declare the `post` module so we can access our `
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(App, |c| c);
dioxus::desktop::launch(App);
}
mod post;
@ -186,7 +186,7 @@ Ultimately, including and exporting components is governed by Rust's module syst
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(App, |c| c);
dioxus::desktop::launch(App);
}
mod post;

View file

@ -64,7 +64,7 @@ The most common hook you'll use for storing state is `use_state`. `use_state` pr
```rust
fn App(cx: Context, props: &())-> Element {
let post = use_state(cx, || {
let post = use_state(&cx, || {
PostData {
id: Uuid::new_v4(),
score: 10,
@ -112,7 +112,7 @@ For example, let's say we provide a button to generate a new post. Whenever the
```rust
fn App(cx: Context, props: &())-> Element {
let post = use_state(cx, || PostData::new());
let post = use_state(&cx, || PostData::new());
cx.render(rsx!{
button {
@ -135,7 +135,7 @@ We can use tasks in our components to build a tiny stopwatch that ticks every se
```rust
fn App(cx: Context, props: &())-> Element {
let mut sec_elapsed = use_state(cx, || 0);
let mut sec_elapsed = use_state(&cx, || 0);
cx.spawn_task(async move {
TimeoutFuture::from_ms(1000).await;

View file

@ -92,7 +92,7 @@ use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(App, |c| c);
dioxus::desktop::launch(App);
}
fn App(cx: Context, props: &()) -> Element {
@ -118,7 +118,7 @@ This initialization code launches a Tokio runtime on a helper thread where your
```rust
fn main() {
dioxus::desktop::launch(App, |c| c);
dioxus::desktop::launch(App);
}
```
@ -135,7 +135,7 @@ fn App(cx: Context, props: &()) -> Element {
Writing `fn App(cx: Context, props: &()) -> Element {` might become tedious. Rust will also let you write functions as static closures, but these types of Components cannot have props that borrow data.
```rust
static App: FC<()> = |cx, props| cx.render(rsx!(div { "Hello, world!" }));
static App: Component<()> = |cx, props| cx.render(rsx!(div { "Hello, world!" }));
```
### What is this `Context` object?

View file

@ -72,7 +72,7 @@ fn App(cx: Context, props: &()) -> Element {
struct ToggleProps { children: Element }
fn Toggle(cx: Context, props: &ToggleProps) -> Element {
let mut toggled = use_state(cx, || false);
let mut toggled = use_state(&cx, || false);
cx.render(rsx!{
div {
{&props.children}
@ -87,7 +87,7 @@ fn Toggle(cx: Context, props: &ToggleProps) -> Element {
Controlled inputs:
```rust
fn App(cx: Context, props: &()) -> Element {
let value = use_state(cx, String::new);
let value = use_state(&cx, String::new);
cx.render(rsx!(
input {
"type": "text",
@ -123,13 +123,13 @@ fn App(cx: Context, props: &()) -> Element {
Tiny components:
```rust
static App: FC<()> = |cx, _| rsx!(cx, div {"hello world!"});
static App: Component<()> = |cx, _| rsx!(cx, div {"hello world!"});
```
Borrowed prop contents:
```rust
fn App(cx: Context, props: &()) -> Element {
let name = use_state(cx, || String::from("example"));
let name = use_state(&cx, || String::from("example"));
rsx!(cx, Child { title: name.as_str() })
}
@ -137,7 +137,7 @@ fn App(cx: Context, props: &()) -> Element {
struct ChildProps<'a> { title: &'a str }
fn Child(cx: Context, props: &ChildProps) -> Element {
rsx!(cx, "Hello {props.title}")
rsx!(cx, "Hello {cx.props.title}")
}
```

View file

@ -8,12 +8,12 @@ use gloo_timers::future::TimeoutFuture;
#[tokio::main]
async fn main() {
dioxus::desktop::launch(App, |c| c);
dioxus::desktop::launch(App);
}
pub static App: Component<()> = |cx, _| {
let count = use_state(cx, || 0);
let mut direction = use_state(cx, || 1);
pub static App: Component<()> = |cx| {
let count = use_state(&cx, || 0);
let mut direction = use_state(&cx, || 1);
let (async_count, dir) = (count.for_async(), *direction);

View file

@ -17,10 +17,10 @@ and is proven to be safe with MIRI.
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(App, |c| c);
dioxus::desktop::launch(App);
}
fn App(cx: Scope, props: &()) -> Element {
fn App(cx: Scope<()>) -> Element {
let text: &mut Vec<String> = cx.use_hook(|_| vec![String::from("abc=def")], |f| f);
let first = text.get_mut(0).unwrap();
@ -39,7 +39,7 @@ struct C1Props<'a> {
text: &'a mut String,
}
fn Child1(cx: Scope, props: &C1Props) -> Element {
fn Child1<'a>(cx: Scope<'a, C1Props<'a>>) -> Element {
let (left, right) = props.text.split_once("=").unwrap();
cx.render(rsx! {
@ -55,7 +55,7 @@ struct C2Props<'a> {
text: &'a str,
}
fn Child2(cx: Scope, props: &C2Props) -> Element {
fn Child2<'a>(cx: Scope<'a, C2Props<'a>>) -> Element {
cx.render(rsx! {
Child3 {
text: props.text
@ -68,8 +68,8 @@ struct C3Props<'a> {
text: &'a str,
}
fn Child3(cx: Scope, props: &C3Props) -> Element {
fn Child3<'a>(cx: Scope<'a, C3Props<'a>>) -> Element {
cx.render(rsx! {
div { "{props.text}"}
div { "{cx.props.text}"}
})
}

View file

@ -10,13 +10,13 @@ use dioxus::prelude::*;
use separator::Separatable;
fn main() {
dioxus::desktop::launch(APP, |cfg| cfg);
dioxus::desktop::launch(APP);
}
const APP: Component<()> = |cx, _| {
let cur_val = use_state(cx, || 0.0_f64);
let operator = use_state(cx, || None as Option<&'static str>);
let display_value = use_state(cx, || String::from(""));
static APP: Component<()> = |cx| {
let cur_val = use_state(&cx, || 0.0_f64);
let operator = use_state(&cx, || None as Option<&'static str>);
let display_value = use_state(&cx, || String::from(""));
let toggle_percent = move |_| todo!();
let input_digit = move |num: u8| display_value.modify().push_str(num.to_string().as_str());
@ -117,13 +117,13 @@ const APP: Component<()> = |cx, _| {
struct CalculatorKeyProps<'a> {
name: &'static str,
onclick: &'a dyn Fn(Arc<MouseEvent>),
children: Element,
children: Element<'a>,
}
fn CalculatorKey<'a>(cx: Scope, props: &CalculatorKeyProps) -> Element {
fn CalculatorKey<'a>(cx: Scope<'a, CalculatorKeyProps<'a>>) -> Element {
rsx!(cx, button {
class: "calculator-key {props.name}"
onclick: {props.onclick}
class: "calculator-key {cx.props.name}"
onclick: {cx.props.onclick}
{&props.children}
})
}

View file

@ -9,7 +9,7 @@ fn main() {
println!("{}", dom);
}
pub static EXAMPLE: FC<()> = |cx, _| {
pub static EXAMPLE: Component<()> = |cx| {
let list = (0..10).map(|_f| {
rsx! {
"{_f}"

View file

@ -5,7 +5,7 @@ fn main() {
dom.rebuild();
}
const App: FC<()> = |cx, props| {
const App: Component<()> = |cx| {
let id = cx.scope_id();
// cx.submit_task(Box::pin(async move { id }));

View file

@ -6,7 +6,7 @@ struct SomeContext {
}
#[allow(unused)]
static Example: FC<()> = |cx, props| {
static Example: Component<()> = |cx| {
todo!()
// let value = cx.use_context(|c: &SomeContext| c.items.last().unwrap());

View file

@ -47,9 +47,9 @@ fn Row<'a>((cx, props): Scope<'a, RowProps>) -> Element<'a> {
};
cx.render(rsx! {
tr {
// td { class:"col-md-1", "{props.row_id}" }
// td { class:"col-md-1", "{cx.props.row_id}" }
// td { class:"col-md-1", onclick: move |_| { /* run onselect */ }
// a { class: "lbl", "{props.label}" }
// a { class: "lbl", "{cx.props.label}" }
// }
// td { class: "col-md-1"
// a { class: "remove", onclick: {handler}

View file

@ -31,9 +31,9 @@ fn html_usage() {
// let p = rsx!(div { {f} });
}
static App2: FC<()> = |cx, _| cx.render(rsx!("hello world!"));
static App2: Component<()> = |cx, _| cx.render(rsx!("hello world!"));
static App: FC<()> = |cx, props| {
static App: Component<()> = |cx| {
let name = cx.use_state(|| 0);
cx.render(rsx!(div {
@ -71,7 +71,7 @@ struct ChildProps {
fn Child<'a>((cx, props): Scope<'a, ChildProps>) -> Element<'a> {
cx.render(rsx!(div {
// {props.children}
// {cx.props.children}
}))
}
@ -99,7 +99,7 @@ impl<'a> Children<'a> {
}
}
static Bapp: FC<()> = |cx, props| {
static Bapp: Component<()> = |cx| {
let name = cx.use_state(|| 0);
cx.render(rsx!(
@ -114,7 +114,7 @@ static Bapp: FC<()> = |cx, props| {
))
};
static Match: FC<()> = |cx, props| {
static Match: Component<()> = |cx| {
//
let b: Box<dyn Fn(NodeFactory) -> VNode> = Box::new(|f| todo!());

View file

@ -40,7 +40,7 @@ fn t() {
// let a = rsx! {
// div {
// "asd"
// "{props.foo}"
// "{cx.props.foo}"
// }
// };

View file

@ -4,7 +4,7 @@ use dioxus_core::{lazynodes::LazyNodes, prelude::*};
// #[async_std::main]
fn main() {
static App: FC<()> =
static App: Component<()> =
|cx, props| cx.render(Some(LazyNodes::new(move |f| f.text(format_args!("hello")))));
let mut dom = VirtualDom::new(App);

View file

@ -32,14 +32,14 @@ use dioxus::prelude::*;
struct NoKeysProps {
data: std::collections::HashMap<u32, String>,
}
static AntipatternNoKeys: FC<NoKeysProps> = |cx, props| {
static AntipatternNoKeys: Component<NoKeysProps> = |cx| {
// WRONG: Make sure to add keys!
rsx!(cx, ul {
{props.data.iter().map(|(k, v)| rsx!(li { "List item: {v}" }))}
{cx.props.data.iter().map(|(k, v)| rsx!(li { "List item: {v}" }))}
});
// RIGHT: Like this:
rsx!(cx, ul {
{props.data.iter().map(|(k, v)| rsx!(li { key: "{k}", "List item: {v}" }))}
{cx.props.data.iter().map(|(k, v)| rsx!(li { key: "{k}", "List item: {v}" }))}
})
};
@ -54,7 +54,7 @@ static AntipatternNoKeys: FC<NoKeysProps> = |cx, props| {
///
/// Only Component and Fragment nodes are susceptible to this issue. Dioxus mitigates this with components by providing
/// an API for registering shared state without the ContextProvider pattern.
static AntipatternNestedFragments: FC<()> = |cx, props| {
static AntipatternNestedFragments: Component<()> = |cx| {
// Try to avoid heavily nesting fragments
rsx!(cx,
Fragment {
@ -82,8 +82,8 @@ static AntipatternNestedFragments: FC<()> = |cx, props| {
/// However, calling set_state will *not* update the current version of state in the component. This should be easy to
/// recognize from the function signature, but Dioxus will not update the "live" version of state. Calling `set_state`
/// merely places a new value in the queue and schedules the component for a future update.
static AntipatternRelyingOnSetState: FC<()> = |cx, props| {
let (state, set_state) = use_state(cx, || "Hello world").classic();
static AntipatternRelyingOnSetState: Component<()> = |cx| {
let (state, set_state) = use_state(&cx, || "Hello world").classic();
set_state("New state");
// This will return false! `state` will *still* be "Hello world"
assert!(state == &"New state");
@ -99,7 +99,7 @@ static AntipatternRelyingOnSetState: FC<()> = |cx, props| {
/// - All components must start with an uppercase character
///
/// i.e.: the following component will be rejected when attempted to be used in the rsx! macro
static antipattern_component: FC<()> = |cx, props| todo!();
static antipattern_component: Component<()> = |cx, props| todo!();
/// Antipattern: Misusing hooks
/// ---------------------------
@ -120,11 +120,11 @@ static antipattern_component: FC<()> = |cx, props| todo!();
struct MisuedHooksProps {
should_render_state: bool,
}
static AntipatternMisusedHooks: FC<MisuedHooksProps> = |cx, props| {
static AntipatternMisusedHooks: Component<MisuedHooksProps> = |cx| {
if props.should_render_state {
// do not place a hook in the conditional!
// prefer to move it out of the conditional
let (state, set_state) = use_state(cx, || "hello world").classic();
let (state, set_state) = use_state(&cx, || "hello world").classic();
rsx!(cx, div { "{state}" })
} else {
rsx!(cx, div { "Not rendering state" })
@ -153,7 +153,7 @@ static AntipatternMisusedHooks: FC<MisuedHooksProps> = |cx, props| {
/// }
/// }
/// })
static _example: FC<()> = |cx, props| todo!();
static _example: Component<()> = |cx, props| todo!();
/// Antipattern: publishing components and hooks with all features enabled
/// ----------------------------------------------------------------------
@ -171,9 +171,9 @@ static _example: FC<()> = |cx, props| todo!();
///
/// This will only include the `core` dioxus crate which is relatively slim and fast to compile and avoids target-specific
/// libraries.
static __example: FC<()> = |cx, props| todo!();
static __example: Component<()> = |cx, props| todo!();
pub static Example: FC<()> = |cx, props| {
pub static Example: Component<()> = |cx| {
cx.render(rsx! {
AntipatternNoKeys { data: std::collections::HashMap::new() }
AntipatternNestedFragments {}

View file

@ -9,7 +9,7 @@
use dioxus::prelude::*;
pub static Example: FC<()> = |cx, props| {
pub static Example: Component<()> = |cx| {
cx.render(rsx! {
div {
Greeting {
@ -25,10 +25,10 @@ struct GreetingProps {
name: &'static str,
}
static Greeting: FC<GreetingProps> = |cx, props| {
static Greeting: Component<GreetingProps> = |cx| {
cx.render(rsx! {
div {
h1 { "Hello, {props.name}!" }
h1 { "Hello, {cx.props.name}!" }
p { "Welcome to the Dioxus framework" }
br {}
{cx.children()}

View file

@ -18,7 +18,7 @@
use dioxus::prelude::*;
pub static Example: FC<()> = |cx, props| {
pub static Example: Component<()> = |cx| {
cx.render(rsx! {
div {
Banner {
@ -31,7 +31,7 @@ pub static Example: FC<()> = |cx, props| {
})
};
pub static Banner: FC<()> = |cx, props| {
pub static Banner: Component<()> = |cx| {
cx.render(rsx! {
div {
h1 { "This is a great banner!" }

View file

@ -16,10 +16,10 @@ use dioxus::prelude::*;
pub struct MyProps {
should_show: bool,
}
pub static Example0: FC<MyProps> = |cx, props| {
pub static Example0: Component<MyProps> = |cx| {
cx.render(rsx! {
div {
{props.should_show.then(|| rsx!{
{cx.props.should_show.then(|| rsx!{
h1 { "showing the title!" }
})}
}
@ -39,7 +39,7 @@ pub static Example0: FC<MyProps> = |cx, props| {
pub struct MyProps1 {
should_show: bool,
}
pub static Example1: FC<MyProps1> = |cx, props| {
pub static Example1: Component<MyProps1> = |cx| {
cx.render(rsx! {
div {
// With matching
@ -77,7 +77,7 @@ pub enum Color {
pub struct MyProps2 {
color: Color,
}
pub static Example2: FC<MyProps2> = |cx, props| {
pub static Example2: Component<MyProps2> = |cx| {
cx.render(rsx! {
div {
{match props.color {
@ -89,9 +89,9 @@ pub static Example2: FC<MyProps2> = |cx, props| {
})
};
pub static Example: FC<()> = |cx, props| {
let should_show = use_state(cx, || false);
let mut color_index = use_state(cx, || 0);
pub static Example: Component<()> = |cx| {
let should_show = use_state(&cx, || false);
let mut color_index = use_state(&cx, || 0);
let color = match *color_index % 2 {
2 => Color::Green,
1 => Color::Yellow,

View file

@ -1,7 +1,7 @@
use dioxus::prelude::*;
fn main() {}
pub static Example: FC<()> = |cx, props| {
pub static Example: Component<()> = |cx| {
cx.render(rsx! {
div {
@ -10,8 +10,8 @@ pub static Example: FC<()> = |cx, props| {
};
// A controlled component:
static ControlledSelect: FC<()> = |cx, props| {
let value = use_state(cx, || String::from("Grapefruit"));
static ControlledSelect: Component<()> = |cx| {
let value = use_state(&cx, || String::from("Grapefruit"));
cx.render(rsx! {
select { value: "{value}", onchange: move |evt| value.set(evt.value()),
option { value: "Grapefruit", "Grapefruit"}
@ -23,8 +23,8 @@ static ControlledSelect: FC<()> = |cx, props| {
};
// TODO - how do uncontrolled things work?
static UncontrolledSelect: FC<()> = |cx, props| {
let value = use_state(cx, || String::new());
static UncontrolledSelect: Component<()> = |cx| {
let value = use_state(&cx, || String::new());
cx.render(rsx! {
select {

View file

@ -11,7 +11,7 @@
use dioxus::prelude::*;
pub static Example: FC<()> = |cx, props| {
pub static Example: Component<()> = |cx| {
cx.render(rsx! {
div {
custom_element {

View file

@ -5,4 +5,4 @@
use dioxus::prelude::*;
pub static Example: FC<()> = |cx, props| cx.render(rsx! { Fragment {} });
pub static Example: Component<()> = |cx, props| cx.render(rsx! { Fragment {} });

View file

@ -23,14 +23,14 @@ fn main() {}
/// This is one way to go about error handling (just toss things away with unwrap).
/// However, if you get it wrong, the whole app will crash.
/// This is pretty flimsy.
static App: FC<()> = |cx, props| {
static App: Component<()> = |cx| {
let data = get_data().unwrap();
cx.render(rsx!( div { "{data}" } ))
};
/// This is a pretty verbose way of error handling
/// However, it's still pretty good since we don't panic, just fail to render anything
static App1: FC<()> = |cx, props| {
static App1: Component<()> = |cx| {
let data = match get_data() {
Some(data) => data,
None => return None,
@ -46,7 +46,7 @@ static App1: FC<()> = |cx, props| {
/// a user is logged in.
///
/// Dioxus will throw an error in the console if the None-path is ever taken.
static App2: FC<()> = |cx, props| {
static App2: Component<()> = |cx| {
let data = get_data()?;
cx.render(rsx!( div { "{data}" } ))
};
@ -54,14 +54,14 @@ static App2: FC<()> = |cx, props| {
/// This is top-tier error handling since it displays a failure state.
///
/// However, the error is lacking in context.
static App3: FC<()> = |cx, props| match get_data() {
static App3: Component<()> = |cx, props| match get_data() {
Some(data) => cx.render(rsx!( div { "{data}" } )),
None => cx.render(rsx!( div { "Failed to load data :(" } )),
};
/// For errors that return results, it's possible to short-circuit the match-based error handling with `.ok()` which converts
/// a Result<T, V> into an Option<T> and lets you abort rendering by early-returning `None`
static App4: FC<()> = |cx, props| {
static App4: Component<()> = |cx| {
let data = get_data_err().ok()?;
cx.render(rsx!( div { "{data}" } ))
};
@ -69,7 +69,7 @@ static App4: FC<()> = |cx, props| {
/// This is great error handling since it displays a failure state... with context!
///
/// Hopefully you'll never need to display a screen like this. It's rather bad taste
static App5: FC<()> = |cx, props| match get_data_err() {
static App5: Component<()> = |cx, props| match get_data_err() {
Ok(data) => cx.render(rsx!( div { "{data}" } )),
Err(c) => cx.render(rsx!( div { "Failed to load data: {c}" } )),
};

View file

@ -11,7 +11,7 @@
use dioxus::prelude::*;
// Returning multiple elements with rsx! or html!
static App1: FC<()> = |cx, props| {
static App1: Component<()> = |cx| {
cx.render(rsx! {
h1 { }
h2 { }
@ -20,7 +20,7 @@ static App1: FC<()> = |cx, props| {
};
// Using the Fragment component
static App2: FC<()> = |cx, props| {
static App2: Component<()> = |cx| {
cx.render(rsx! {
Fragment {
div {}
@ -31,7 +31,7 @@ static App2: FC<()> = |cx, props| {
};
// Using the `fragment` method on the NodeFactory
static App3: FC<()> = |cx, props| {
static App3: Component<()> = |cx| {
cx.render(LazyNodes::new(move |fac| {
fac.fragment_from_iter([
fac.text(format_args!("A")),
@ -42,7 +42,7 @@ static App3: FC<()> = |cx, props| {
}))
};
pub static Example: FC<()> = |cx, props| {
pub static Example: Component<()> = |cx| {
cx.render(rsx! {
App1 {}
App2 {}

View file

@ -19,7 +19,7 @@ h1 {color: blue;}
p {color: red;}
"#;
pub static Example: FC<()> = |cx, props| {
pub static Example: Component<()> = |cx| {
cx.render(rsx! {
head { style { "{STYLE}" } }
body {

View file

@ -10,7 +10,7 @@
use dioxus::prelude::*;
pub static Example: FC<()> = |cx, props| {
pub static Example: Component<()> = |cx| {
cx.render(rsx! {
head {
style: { background_color: "powderblue" }
@ -29,7 +29,7 @@ pub static Example: FC<()> = |cx, props| {
// .... technically the rsx! macro is slightly broken at the moment and allows styles not wrapped in style {}
// I haven't noticed any name collisions yet, and am tentatively leaving this behavior in..
// Don't rely on it.
static Example2: FC<()> = |cx, props| {
static Example2: Component<()> = |cx| {
cx.render(rsx! {
div { color: "red"
"hello world!"

View file

@ -12,8 +12,8 @@
use dioxus::prelude::*;
pub static Example: FC<()> = |cx, props| {
let example_data = use_state(cx, || 0);
pub static Example: Component<()> = |cx| {
let example_data = use_state(&cx, || 0);
let v = (0..10).map(|f| {
rsx! {

View file

@ -7,7 +7,7 @@
use dioxus::prelude::*;
pub static Example: FC<()> = |cx, props| {
pub static Example: Component<()> = |cx| {
cx.render(rsx! {
ButtonList {}
NonUpdatingEvents {}
@ -16,8 +16,8 @@ pub static Example: FC<()> = |cx, props| {
};
/// We can use `set_name` in multiple closures; the closures automatically *copy* the reference to set_name.
static ButtonList: FC<()> = |cx, props| {
let name = use_state(cx, || "...?");
static ButtonList: Component<()> = |cx| {
let name = use_state(&cx, || "...?");
let names = ["jack", "jill", "john", "jane"]
.iter()
@ -33,7 +33,7 @@ static ButtonList: FC<()> = |cx, props| {
/// This shows how listeners may be without a visible change in the display.
/// Check the console.
static NonUpdatingEvents: FC<()> = |cx, props| {
static NonUpdatingEvents: Component<()> = |cx| {
rsx!(cx, div {
button {
onclick: move |_| log::info!("Did not cause any updates!")
@ -42,7 +42,7 @@ static NonUpdatingEvents: FC<()> = |cx, props| {
})
};
static DisablePropagation: FC<()> = |cx, props| {
static DisablePropagation: Component<()> = |cx| {
rsx!(cx,
div {
onclick: move |_| log::info!("event propagated to the div!")

View file

@ -21,7 +21,7 @@ use dioxus::prelude::*;
// By default, components with no props are always memoized.
// A props of () is considered empty.
pub static Example: FC<()> = |cx, props| {
pub static Example: Component<()> = |cx| {
cx.render(rsx! {
div { "100% memoized!" }
})
@ -35,9 +35,9 @@ pub struct MyProps1 {
name: String,
}
pub static Example1: FC<MyProps1> = |cx, props| {
pub static Example1: Component<MyProps1> = |cx| {
cx.render(rsx! {
div { "100% memoized! {props.name}" }
div { "100% memoized! {cx.props.name}" }
})
};
@ -49,9 +49,9 @@ pub struct MyProps2 {
name: std::rc::Rc<str>,
}
pub static Example2: FC<MyProps2> = |cx, props| {
pub static Example2: Component<MyProps2> = |cx| {
cx.render(rsx! {
div { "100% memoized! {props.name}" }
div { "100% memoized! {cx.props.name}" }
})
};
@ -61,11 +61,11 @@ pub struct MyProps3<'a> {
name: &'a str,
}
// We need to manually specify a lifetime that ensures props and scope (the component's state) share the same lifetime.
// Using the `pub static Example: FC<()>` pattern _will_ specify a lifetime, but that lifetime will be static which might
// Using the `pub static Example: Component<()>` pattern _will_ specify a lifetime, but that lifetime will be static which might
// not exactly be what you want
fn Example3<'a>(cx: Context<'a>, props: &'a MyProps3) -> DomTree<'a> {
cx.render(rsx! {
div { "Not memoized! {props.name}" }
div { "Not memoized! {cx.props.name}" }
})
}

View file

@ -1,7 +1,7 @@
use dioxus::prelude::*;
fn main() {}
pub static Example: FC<()> = |cx, props| {
pub static Example: Component<()> = |cx| {
let p = 10;
cx.render(rsx! {

View file

@ -1,7 +1,7 @@
use dioxus::prelude::*;
fn main() {}
pub static Example: FC<()> = |cx, props| {
pub static Example: Component<()> = |cx| {
cx.render(rsx! {
div {

View file

@ -9,7 +9,7 @@
use dioxus::prelude::*;
pub static Example: FC<()> = |cx, props| {
pub static Example: Component<()> = |cx| {
let props = MyProps {
count: 0,
live: true,
@ -27,7 +27,7 @@ pub struct MyProps {
name: &'static str,
}
pub static Example1: FC<MyProps> = |cx, MyProps { count, live, name }| {
pub static Example1: Component<MyProps> = |cx, MyProps { count, live, name }| {
cx.render(rsx! {
div {
h1 { "Hello, {name}"}

View file

@ -1,7 +1,7 @@
use dioxus::prelude::*;
fn main() {}
pub static Example: FC<()> = |cx, props| {
pub static Example: Component<()> = |cx| {
cx.render(rsx! {
div {

View file

@ -14,7 +14,7 @@ struct DogApi {
}
const ENDPOINT: &str = "https://dog.ceo/api/breeds/image/random";
pub static Example: FC<()> = |cx, props| {
pub static Example: Component<()> = |cx| {
let doggo = use_suspense(
cx,
|| surf::get(ENDPOINT).recv_json::<DogApi>(),

View file

@ -24,9 +24,9 @@
use dioxus::prelude::*;
pub static Example: FC<()> = |cx, props| {
let count = use_state(cx, || 0);
let mut direction = use_state(cx, || 1);
pub static Example: Component<()> = |cx| {
let count = use_state(&cx, || 0);
let mut direction = use_state(&cx, || 1);
// Tasks are 'static, so we need to copy relevant items in
let (async_count, dir) = (count.for_async(), *direction);

View file

@ -1,6 +1,6 @@
use dioxus::prelude::*;
pub static Example: FC<()> = |cx, props| {
pub static Example: Component<()> = |cx| {
cx.render(rsx! {
div {

View file

@ -1,13 +1,13 @@
use dioxus::prelude::*;
use dioxus::ssr;
pub static Example: FC<()> = |cx, props| {
let as_string = use_state(cx, || {
pub static Example: Component<()> = |cx| {
let as_string = use_state(&cx, || {
// Currently, SSR is only supported for whole VirtualDOMs
// This is an easy/low hanging fruit to improve upon
let mut dom = VirtualDom::new(SomeApp);
dom.rebuild();
ssr::render_vdom(&dom, |c| c)
ssr::render_vdom(&dom)
});
cx.render(rsx! {
@ -15,7 +15,7 @@ pub static Example: FC<()> = |cx, props| {
})
};
static SomeApp: FC<()> = |cx, props| {
static SomeApp: Component<()> = |cx| {
cx.render(rsx! {
div { style: {background_color: "blue"}
h1 {"Some amazing app or component"}

View file

@ -22,14 +22,14 @@
//! the coroutine was initiated. `use_state` always returns the same setter, so you don't need to worry about
fn main() {
dioxus::desktop::launch(App, |c| c);
dioxus::desktop::launch(App);
}
use dioxus::prelude::*;
static App: Component<()> = |cx, props| {
let p1 = use_state(cx, || 0);
let p2 = use_state(cx, || 0);
static App: Component<()> = |cx| {
let p1 = use_state(&cx, || 0);
let p2 = use_state(&cx, || 0);
let (mut p1_async, mut p2_async) = (p1.for_async(), p2.for_async());
let (p1_handle, _) = use_coroutine(cx, || async move {

View file

@ -4,7 +4,7 @@ Tiny CRM: A port of the Yew CRM example to Dioxus.
use dioxus::prelude::*;
fn main() {
dioxus::web::launch(App, |c| c);
dioxus::web::launch(App);
}
enum Scene {
ClientsList,
@ -19,13 +19,13 @@ pub struct Client {
pub description: String,
}
static App: Component<()> = |cx, _| {
let mut clients = use_ref(cx, || vec![] as Vec<Client>);
let mut scene = use_state(cx, || Scene::ClientsList);
static App: Component<()> = |cx| {
let mut clients = use_ref(&cx, || vec![] as Vec<Client>);
let mut scene = use_state(&cx, || Scene::ClientsList);
let mut firstname = use_state(cx, || String::new());
let mut lastname = use_state(cx, || String::new());
let mut description = use_state(cx, || String::new());
let mut firstname = use_state(&cx, || String::new());
let mut lastname = use_state(&cx, || String::new());
let mut description = use_state(&cx, || String::new());
let scene = match *scene {
Scene::ClientsList => {

View file

@ -5,7 +5,7 @@ use dioxus_hooks::*;
use dioxus_html as dioxus_elements;
fn main() {
dioxus_desktop::launch(App, |c| c)
dioxus_desktop::launch(App)
}
enum Scene {
@ -21,13 +21,13 @@ pub struct Client {
pub description: String,
}
static App: FC<()> = |cx, _| {
let mut scene = use_state(cx, || Scene::ClientsList);
let clients = use_ref(cx, || vec![] as Vec<Client>);
static App: Component<()> = |cx| {
let mut scene = use_state(&cx, || Scene::ClientsList);
let clients = use_ref(&cx, || vec![] as Vec<Client>);
let mut firstname = use_state(cx, String::new);
let mut lastname = use_state(cx, String::new);
let mut description = use_state(cx, String::new);
let mut firstname = use_state(&cx, String::new);
let mut lastname = use_state(&cx, String::new);
let mut description = use_state(&cx, String::new);
let scene = match scene.get() {
Scene::ClientsList => {

View file

@ -5,10 +5,10 @@ use dioxus_core_macro::*;
use dioxus_html as dioxus_elements;
fn main() {
dioxus_desktop::launch(App, |c| c);
dioxus_desktop::launch(App);
}
static App: FC<()> = |cx, props| {
static App: Component<()> = |cx| {
cx.render(rsx!(
div {
"hello world!"

View file

@ -14,7 +14,7 @@ fn main() {
SimpleLogger::new().init().unwrap();
}
dioxus_desktop::launch(App, |c| c)
dioxus_desktop::launch(App)
}
#[derive(PartialEq)]
@ -32,14 +32,14 @@ pub struct TodoItem {
}
pub type Todos = HashMap<u32, TodoItem>;
pub static App: FC<()> = |cx, _| {
pub static App: Component<()> = |cx| {
// Share our TodoList to the todos themselves
use_provide_state(cx, Todos::new);
// Save state for the draft, filter
let draft = use_state(cx, || "".to_string());
let filter = use_state(cx, || FilterState::All);
let mut todo_id = use_state(cx, || 0);
let draft = use_state(&cx, || "".to_string());
let filter = use_state(&cx, || FilterState::All);
let mut todo_id = use_state(&cx, || 0);
// Consume the todos
let todos = use_shared_state::<Todos>(cx)?;
@ -142,7 +142,7 @@ pub fn TodoEntry((cx, props): Scope<TodoEntryProps>) -> Element {
let _todos = todos.read();
let todo = _todos.get(&props.id)?;
let is_editing = use_state(cx, || false);
let is_editing = use_state(&cx, || false);
let completed = if todo.checked { "completed" } else { "" };
cx.render(rsx!{

View file

@ -9,7 +9,7 @@ use dioxus::prelude::*;
fn main() {
simple_logger::init_with_level(log::Level::Debug);
dioxus::desktop::launch(App, |c| {
dioxus::desktop::launch_cfg(App, |c| {
c.with_window(|w| {
w.with_resizable(true).with_inner_size(
dioxus::desktop::wry::application::dpi::LogicalSize::new(400.0, 800.0),
@ -18,8 +18,8 @@ fn main() {
});
}
static App: Component<()> = |cx, props| {
let file_manager = use_ref(cx, || Files::new());
static App: Component<()> = |cx| {
let file_manager = use_ref(&cx, Files::new);
let files = file_manager.read();
let file_list = files.path_names.iter().enumerate().map(|(dir_id, path)| {
@ -39,13 +39,15 @@ static App: Component<()> = |cx, props| {
let current_dir = files.current();
rsx!(cx, div {
h1 {"Files: "}
h3 {"Cur dir: {current_dir}"}
button { "go up", onclick: move |_| file_manager.write().go_up() }
ol { {file_list} }
{err_disp}
})
cx.render(rsx!(
div {
h1 {"Files: "}
h3 {"Cur dir: {current_dir}"}
button { "go up", onclick: move |_| file_manager.write().go_up() }
ol { {file_list} }
{err_disp}
}
))
};
struct Files {

View file

@ -2,8 +2,8 @@ use dioxus::prelude::*;
use rand::prelude::*;
fn main() {
dioxus::web::launch(App, |c| c);
// dioxus::desktop::launch(App, |c| c);
dioxus::web::launch(App);
// dioxus::desktop::launch(App);
}
#[derive(Clone, PartialEq)]
@ -30,9 +30,9 @@ impl Label {
}
}
static App: Component<()> = |cx, _props| {
let mut items = use_ref(cx, || vec![]);
let mut selected = use_state(cx, || None);
static App: Component<()> = |cx| {
let mut items = use_ref(&cx, || vec![]);
let mut selected = use_state(&cx, || None);
cx.render(rsx! {
div { class: "container"
@ -95,10 +95,10 @@ struct ActionButtonProps<'a> {
onclick: &'a dyn Fn(),
}
fn ActionButton(cx: Scope, props: &ActionButtonProps) -> Element {
fn ActionButton<'a>(cx: Scope<'a, ActionButtonProps<'a>>) -> Element {
rsx!(cx, div { class: "col-sm-6 smallpad"
button { class:"btn btn-primary btn-block", r#type: "button", id: "{props.id}", onclick: move |_| (props.onclick)(),
"{props.name}"
button { class:"btn btn-primary btn-block", r#type: "button", id: "{cx.props.id}", onclick: move |_| (props.onclick)(),
"{cx.props.name}"
}
})
}
@ -149,9 +149,9 @@ static NOUNS: &[&str] = &[
// fn Row(cx: Context, props: &RowProps) -> Element {
// rsx!(cx, tr {
// td { class:"col-md-1", "{props.row_id}" }
// td { class:"col-md-1", "{cx.props.row_id}" }
// td { class:"col-md-1", onclick: move |_| { /* run onselect */ }
// a { class: "lbl", {props.label.labels} }
// a { class: "lbl", {cx.props.label.labels} }
// }
// td { class: "col-md-1"
// a { class: "remove", onclick: move |_| {/* remove */}

View file

@ -1,7 +1,7 @@
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(App, |c| c);
dioxus::desktop::launch(App);
}
fn App((cx, props): ScopeState<()>) -> Element {

View file

@ -19,8 +19,8 @@ fn main() {
dioxus::desktop::launch(App, |c| c.with_prerendered(content));
}
static App: Component<()> = |cx, props| {
let mut val = use_state(cx, || 0);
static App: Component<()> = |cx| {
let mut val = use_state(&cx, || 0);
cx.render(rsx! {
div {

View file

@ -16,13 +16,13 @@
//! RefMuts at the same time.
use dioxus::desktop::wry::application::dpi::LogicalSize;
use dioxus::events::{on::*, KeyCode};
use dioxus::events::*;
use dioxus::prelude::*;
const STYLE: &str = include_str!("./assets/calculator.css");
fn main() {
env_logger::init();
dioxus::desktop::launch(App, |cfg| {
dioxus::desktop::launch_cfg(App, |cfg| {
cfg.with_window(|w| {
w.with_title("Calculator Demo")
.with_resizable(false)
@ -31,8 +31,8 @@ fn main() {
});
}
static App: Component<()> = |cx, props| {
let state = use_ref(cx, || Calculator::new());
static App: Component<()> = |cx| {
let state = use_ref(&cx, || Calculator::new());
let clear_display = state.read().display_value.eq("0");
let clear_text = if clear_display { "C" } else { "AC" };
@ -80,8 +80,8 @@ struct CalculatorKeyProps<'a> {
fn CalculatorKey<'a>((cx, props): ScopeState<'a, CalculatorKeyProps<'a>>) -> Element<'a> {
cx.render(rsx! {
button {
class: "calculator-key {props.name}"
onclick: {props.onclick}
class: "calculator-key {cx.props.name}"
onclick: {cx.props.onclick}
{&props.children}
}
})

View file

@ -8,11 +8,11 @@
use dioxus::prelude::*;
fn main() {
env_logger::init();
dioxus::desktop::launch(App, |c| c);
dioxus::desktop::launch(App);
}
pub static App: Component<()> = |cx, _| {
let state = use_state(cx, PlayerState::new);
pub static App: Component<()> = |cx| {
let state = use_state(&cx, PlayerState::new);
let is_playing = state.is_playing();

View file

@ -4,11 +4,11 @@
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(App, |c| c);
dioxus::desktop::launch(App);
}
static App: Component<()> = |cx, props| {
let mut count = use_state(cx, || 0);
static App: Component<()> = |cx| {
let mut count = use_state(&cx, || 0);
cx.render(rsx! {
div {

View file

@ -23,7 +23,7 @@ pub enum Route {
NotFound,
}
static App: Component<()> = |cx, props| {
static App: Component<()> = |cx| {
let route = use_router(cx, Route::parse)?;
cx.render(rsx! {

View file

@ -39,7 +39,7 @@
//! - Allow top-level fragments
//!
fn main() {
dioxus::desktop::launch(Example, |c| c);
dioxus::desktop::launch(Example);
}
/// When trying to return "nothing" to Dioxus, you'll need to specify the type parameter or Rust will be sad.
@ -49,7 +49,7 @@ const NONE_ELEMENT: Option<()> = None;
use baller::Baller;
use dioxus::prelude::*;
pub static Example: Component<()> = |cx, props| {
pub static Example: Component<()> = |cx| {
let formatting = "formatting!";
let formatting_tuple = ("a", "b");
let lazy_fmt = format_args!("lazily formatted text");

View file

@ -5,11 +5,11 @@ use dioxus::ssr;
fn main() {
let mut vdom = VirtualDom::new(App);
// vdom.rebuild_in_place().expect("Rebuilding failed");
println!("{}", ssr::render_vdom(&vdom, |c| c));
vdom.rebuild_in_place().expect("Rebuilding failed");
println!("{}", ssr::render_vdom(&vdom));
}
static App: Component<()> = |cx, props| {
static App: Component<()> = |cx| {
cx.render(rsx!(
div {
h1 { "Title" }
@ -21,6 +21,6 @@ static App: Component<()> = |cx, props| {
struct MyProps<'a> {
text: &'a str,
}
fn App2(cx: Scope, props: &MyProps) -> Element {
fn App2<'a>(cx: Scope<'a, MyProps<'a>>) -> Element {
None
}

View file

@ -12,7 +12,7 @@ fn main() {
)
}
pub static App: FC<()> = |cx, props| {
pub static App: Component<()> = |cx| {
cx.render(rsx!(
div {
class: "overflow-hidden"

View file

@ -26,7 +26,7 @@ fn main() {}
// dom.rebuild();
// Ok(Response::builder(200)
// .body(format!("{}", dioxus_ssr::render_vdom(&dom, |c| c)))
// .body(format!("{}", dioxus_ssr::render_vdom(&dom)))
// .content_type(tide::http::mime::HTML)
// .build())
// });
@ -42,8 +42,8 @@ fn main() {}
// initial_name: String,
// }
// static Example: FC<ExampleProps> = |cx, props| {
// let dispaly_name = use_state(cx, move || props.initial_name.clone());
// static Example: Component<ExampleProps> = |cx| {
// let dispaly_name = use_state(&cx, move || props.initial_name.clone());
// cx.render(rsx! {
// div { class: "py-12 px-4 text-center w-full max-w-2xl mx-auto",

View file

@ -24,7 +24,7 @@ fn main() {
.unwrap();
}
pub static App: FC<()> = |cx, props| {
pub static App: Component<()> = |cx| {
cx.render(rsx!(
div { class: "overflow-hidden"
link { href:"https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel:"stylesheet" }
@ -39,7 +39,7 @@ pub static App: FC<()> = |cx, props| {
))
};
pub static Header: FC<()> = |cx, props| {
pub static Header: Component<()> = |cx| {
cx.render(rsx! {
div {
header { class: "text-gray-400 bg-gray-900 body-font"
@ -65,7 +65,7 @@ pub static Header: FC<()> = |cx, props| {
})
};
pub static Hero: FC<()> = |cx, props| {
pub static Hero: Component<()> = |cx| {
//
cx.render(rsx! {
section{ class: "text-gray-400 bg-gray-900 body-font"
@ -103,7 +103,7 @@ pub static Hero: FC<()> = |cx, props| {
}
})
};
pub static Entry: FC<()> = |cx, props| {
pub static Entry: Component<()> = |cx| {
//
cx.render(rsx! {
section{ class: "text-gray-400 bg-gray-900 body-font"
@ -116,7 +116,7 @@ pub static Entry: FC<()> = |cx, props| {
})
};
pub static StacksIcon: FC<()> = |cx, props| {
pub static StacksIcon: Component<()> = |cx| {
cx.render(rsx!(
svg {
xmlns: "http://www.w3.org/2000/svg"
@ -131,7 +131,7 @@ pub static StacksIcon: FC<()> = |cx, props| {
}
))
};
pub static RightArrowIcon: FC<()> = |cx, props| {
pub static RightArrowIcon: Component<()> = |cx| {
cx.render(rsx!(
svg {
fill: "none"

View file

@ -14,7 +14,7 @@ fn main() {
const STYLE: &str = "body {overflow:hidden;}";
pub static App: Component<()> = |cx, props| {
pub static App: Component<()> = |cx| {
cx.render(rsx!(
div { class: "overflow-hidden"
style { "{STYLE}" }
@ -30,7 +30,7 @@ pub static App: Component<()> = |cx, props| {
))
};
pub static Header: Component<()> = |cx, props| {
pub static Header: Component<()> = |cx| {
cx.render(rsx! {
div {
header { class: "text-gray-400 bg-gray-900 body-font"
@ -56,7 +56,7 @@ pub static Header: Component<()> = |cx, props| {
})
};
pub static Hero: Component<()> = |cx, props| {
pub static Hero: Component<()> = |cx| {
//
cx.render(rsx! {
section{ class: "text-gray-400 bg-gray-900 body-font"
@ -94,7 +94,7 @@ pub static Hero: Component<()> = |cx, props| {
}
})
};
pub static Entry: Component<()> = |cx, props| {
pub static Entry: Component<()> = |cx| {
//
cx.render(rsx! {
section{ class: "text-gray-400 bg-gray-900 body-font"
@ -107,7 +107,7 @@ pub static Entry: Component<()> = |cx, props| {
})
};
pub static StacksIcon: Component<()> = |cx, props| {
pub static StacksIcon: Component<()> = |cx| {
cx.render(rsx!(
svg {
// xmlns: "http://www.w3.org/2000/svg"
@ -122,7 +122,7 @@ pub static StacksIcon: Component<()> = |cx, props| {
}
))
};
pub static RightArrowIcon: Component<()> = |cx, props| {
pub static RightArrowIcon: Component<()> = |cx| {
cx.render(rsx!(
svg {
fill: "none"

View file

@ -6,11 +6,11 @@ use std::time::Duration;
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(App, |c| c);
dioxus::desktop::launch(App);
}
static App: Component<()> = |cx, props| {
let mut count = use_state(cx, || 0);
static App: Component<()> = |cx| {
let mut count = use_state(&cx, || 0);
cx.push_task(async move {
tokio::time::sleep(Duration::from_millis(100)).await;

View file

@ -4,7 +4,7 @@ use im_rc::HashMap;
use std::rc::Rc;
fn main() {
dioxus::desktop::launch(App, |c| c);
dioxus::desktop::launch(App);
}
#[derive(PartialEq)]
@ -22,10 +22,10 @@ pub struct TodoItem {
}
const STYLE: &str = include_str!("./assets/todomvc.css");
const App: Component<()> = |cx, props| {
let mut draft = use_state(cx, || "".to_string());
let mut todos = use_state(cx, || HashMap::<u32, Rc<TodoItem>>::new());
let mut filter = use_state(cx, || FilterState::All);
const App: Component<()> = |cx| {
let mut draft = use_state(&cx, || "".to_string());
let mut todos = use_state(&cx, || HashMap::<u32, Rc<TodoItem>>::new());
let mut filter = use_state(&cx, || FilterState::All);
let todolist = todos
.iter()
@ -85,9 +85,9 @@ pub struct TodoEntryProps {
todo: Rc<TodoItem>,
}
pub fn TodoEntry(cx: Scope, props: &TodoEntryProps) -> Element {
let mut is_editing = use_state(cx, || false);
let mut contents = use_state(cx, || String::from(""));
pub fn TodoEntry(cx: Scope<TodoEntryProps>) -> Element {
let mut is_editing = use_state(&cx, || false);
let mut contents = use_state(&cx, || String::from(""));
let todo = &props.todo;
rsx!(cx, li {

View file

@ -7,12 +7,12 @@
use dioxus::prelude::*;
fn main() {
dioxus::desktop::launch(App, |c| c);
dioxus::desktop::launch(App);
}
const ENDPOINT: &str = "https://api.openweathermap.org/data/2.5/weather";
static App: Component<()> = |cx, props| {
static App: Component<()> = |cx| {
//
let body = use_suspense(
cx,
@ -40,7 +40,7 @@ static App: Component<()> = |cx, props| {
#[derive(PartialEq, Props)]
struct WeatherProps {}
static WeatherDisplay: Component<WeatherProps> = |cx, props| {
static WeatherDisplay: Component<WeatherProps> = |cx| {
//
cx.render(rsx!(
div { class: "flex items-center justify-center flex-col"

View file

@ -8,7 +8,7 @@ use dioxus_html as dioxus_elements;
fn main() {
console_error_panic_hook::set_once();
wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
dioxus_web::launch(APP, |c| c)
dioxus_web::launch(APP)
}
#[derive(serde::Deserialize)]
@ -16,8 +16,8 @@ struct DogApi {
message: String,
}
static APP: FC<()> = |(cx, _props)| {
let state = use_state(cx, || 0);
static APP: Component<()> = |(cx, _props)| {
let state = use_state(&cx, || 0);
const ENDPOINT: &str = "https://dog.ceo/api/breeds/image/random/";
let doggo = use_suspense(

View file

@ -11,13 +11,13 @@ fn main() {
console_error_panic_hook::set_once();
// Run the app
dioxus_web::launch(APP, |c| c)
dioxus_web::launch(APP)
}
static APP: FC<()> = |cx, _| {
let mut count = use_state(cx, || 3);
let content = use_state(cx, || String::from("h1"));
let text_content = use_state(cx, || String::from("Hello, world!"));
static APP: Component<()> = |cx| {
let mut count = use_state(&cx, || 3);
let content = use_state(&cx, || String::from("h1"));
let text_content = use_state(&cx, || String::from("Hello, world!"));
cx.render(rsx! {
div {
@ -86,4 +86,4 @@ fn render_list(cx: Context, count: usize) -> Element {
rsx!(cx, ul { {items} })
}
static CHILD: FC<()> = |cx, _| rsx!(cx, div {"hello child"});
static CHILD: Component<()> = |cx, _| rsx!(cx, div {"hello child"});

View file

@ -21,11 +21,11 @@ fn main() {
console_error_panic_hook::set_once();
// Run the app
dioxus_web::launch(App, |c| c)
dioxus_web::launch(App)
}
static App: FC<()> = |cx, props| {
let mut state = use_state(cx, || 0);
static App: Component<()> = |cx| {
let mut state = use_state(&cx, || 0);
cx.render(rsx! {
div {
style: {

View file

@ -18,12 +18,12 @@ use dioxus_html as dioxus_elements;
// #[cfg]
fn main() {
wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
dioxus_web::launch(App, |c| c);
dioxus_web::launch(App);
// env_logger::init();
// dioxus::web::launch(App, |c| c);
// dioxus::web::launch(App);
}
static App: FC<()> = |cx, props| {
static App: Component<()> = |cx| {
dbg!("rednering parent");
cx.render(rsx! {
div {
@ -40,8 +40,8 @@ static App: FC<()> = |cx, props| {
})
};
static But: FC<()> = |cx, props| {
let mut count = use_state(cx, || 0);
static But: Component<()> = |cx| {
let mut count = use_state(&cx, || 0);
// let d = Dropper { name: "asd" };
// let handler = move |_| {

View file

@ -12,7 +12,7 @@ fn main() {
wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
console_error_panic_hook::set_once();
dioxus_web::launch(App, |c| c)
dioxus_web::launch(App)
}
enum Scene {
@ -28,13 +28,13 @@ pub struct Client {
pub description: String,
}
static App: FC<()> = |cx, _| {
let scene = use_state(cx, || Scene::ClientsList);
let clients = use_ref(cx, || vec![] as Vec<Client>);
static App: Component<()> = |cx| {
let scene = use_state(&cx, || Scene::ClientsList);
let clients = use_ref(&cx, || vec![] as Vec<Client>);
let firstname = use_state(cx, || String::new());
let lastname = use_state(cx, || String::new());
let description = use_state(cx, || String::new());
let firstname = use_state(&cx, || String::new());
let lastname = use_state(&cx, || String::new());
let description = use_state(&cx, || String::new());
let scene = match *scene {
Scene::ClientsList => {

View file

@ -21,10 +21,10 @@ fn main() {
console_error_panic_hook::set_once();
// Run the app
dioxus_web::launch(App, |c| c)
dioxus_web::launch(App)
}
pub static App: FC<()> = |cx, props| {
pub static App: Component<()> = |cx| {
cx.render(rsx!(
div { class: "overflow-hidden"
link { href:"https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel:"stylesheet" }
@ -39,7 +39,7 @@ pub static App: FC<()> = |cx, props| {
))
};
pub static Header: FC<()> = |cx, props| {
pub static Header: Component<()> = |cx| {
cx.render(rsx! {
div {
header { class: "text-gray-400 bg-gray-900 body-font"
@ -65,7 +65,7 @@ pub static Header: FC<()> = |cx, props| {
})
};
pub static Hero: FC<()> = |cx, props| {
pub static Hero: Component<()> = |cx| {
//
cx.render(rsx! {
section{ class: "text-gray-400 bg-gray-900 body-font"
@ -103,7 +103,7 @@ pub static Hero: FC<()> = |cx, props| {
}
})
};
pub static Entry: FC<()> = |cx, props| {
pub static Entry: Component<()> = |cx| {
//
cx.render(rsx! {
section{ class: "text-gray-400 bg-gray-900 body-font"
@ -116,7 +116,7 @@ pub static Entry: FC<()> = |cx, props| {
})
};
pub static StacksIcon: FC<()> = |cx, props| {
pub static StacksIcon: Component<()> = |cx| {
cx.render(rsx!(
svg {
// xmlns: "http://www.w3.org/2000/svg"
@ -131,7 +131,7 @@ pub static StacksIcon: FC<()> = |cx, props| {
}
))
};
pub static RightArrowIcon: FC<()> = |cx, props| {
pub static RightArrowIcon: Component<()> = |cx| {
cx.render(rsx!(
svg {
fill: "none"

View file

@ -16,10 +16,10 @@ fn main() {
#[cfg(target_arch = "wasm32")]
intern_strings();
dioxus::web::launch(App, |c| c);
dioxus::web::launch(App);
}
static App: Component<()> = |cx, props| {
static App: Component<()> = |cx| {
let mut rng = SmallRng::from_entropy();
let rows = (0..1_000).map(|f| {
let label = Label::new(&mut rng);
@ -49,7 +49,7 @@ fn Row((cx, props): ScopeState<RowProps>) -> Element {
let [adj, col, noun] = props.label.0;
cx.render(rsx! {
tr {
td { class:"col-md-1", "{props.row_id}" }
td { class:"col-md-1", "{cx.props.row_id}" }
td { class:"col-md-1", onclick: move |_| { /* run onselect */ }
a { class: "lbl", "{adj}" "{col}" "{noun}" }
}

View file

@ -13,11 +13,11 @@
use dioxus::prelude::*;
fn main() {
dioxus::web::launch(App, |c| c);
dioxus::web::launch(App);
}
static App: Component<()> = |cx, props| {
let mut count = use_state(cx, || 0);
static App: Component<()> = |cx| {
let mut count = use_state(&cx, || 0);
cx.render(rsx! {
div {

View file

@ -12,7 +12,7 @@ https://github.com/rustwasm/gloo
For example, resize observer would function like this:
```rust
pub static Example: FC<()> = |cx, props|{
pub static Example: Component<()> = |cx, props|{
let observer = use_resize_observer();
cx.render(rsx!(

View file

@ -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
pub static Example: FC<()> = |cx, props|{
pub static Example: Component<()> = |cx, props|{
html! { <div> "blah" </div> }
};
// expands to...
pub static Example: FC<()> = |cx, props|{
pub static Example: Component<()> = |cx, props|{
// This function converts a Fn(allocator) -> DomTree closure to a VNode struct that will later be evaluated.
html_macro_to_vnodetree(move |allocator| {
let mut node0 = allocator.alloc(VElement::div);
@ -313,7 +313,7 @@ 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<()> = |cx, props|{
static APP: Component<()> = |cx, props|{
let title = use_context(Title);
cx.render(html!{
<div>
@ -334,7 +334,7 @@ static APP: FC<()> = |cx, props|{
</div>
})
};
static HEAVY_LIST: FC<()> = |cx, props|{
static HEAVY_LIST: Component<()> = |cx, props|{
cx.render({
{0.100.map(i => <BigElement >)}
})
@ -378,7 +378,7 @@ struct Props {
}
static Component: FC<Props> = |cx, props|{
static Component: Component<Props> = |cx, props|{
}
```

View file

@ -30,7 +30,7 @@ pub fn derive_typed_builder(input: proc_macro::TokenStream) -> proc_macro::Token
///
/// ## Complete Reference Guide:
/// ```
/// const Example: FC<()> = |cx, props|{
/// const Example: Component<()> = |cx, props|{
/// let formatting = "formatting!";
/// let formatting_tuple = ("a", "b");
/// let lazy_fmt = format_args!("lazily formatted text");

View file

@ -43,7 +43,11 @@ impl Parse for AmbiguousElement {
if first_char.is_ascii_uppercase() {
input.parse::<Component>().map(AmbiguousElement::Component)
} else {
input.parse::<Element>().map(AmbiguousElement::Element)
if input.peek2(syn::token::Paren) {
input.parse::<Component>().map(AmbiguousElement::Component)
} else {
input.parse::<Element>().map(AmbiguousElement::Element)
}
}
} else {
Err(Error::new(input.span(), "Not a valid Html tag"))

View file

@ -39,7 +39,14 @@ impl Parse for Component {
// parse the guts
let content: ParseBuffer;
syn::braced!(content in stream);
// if we see a `{` then we have a block
// else parse as a function-like call
if stream.peek(token::Brace) {
syn::braced!(content in stream);
} else {
syn::parenthesized!(content in stream);
}
let cfg: BodyConfig = BodyConfig {
allow_children: true,

View file

@ -22,7 +22,7 @@ longest-increasing-subsequence = "0.1.0"
# internall used
log = { version = "0.4", features = ["release_max_level_off"] }
futures-util = { version = "0.3.15", default-features = false }
futures-util = { version = "0.3", default-features = false }
smallvec = "1.6"
@ -48,7 +48,7 @@ fern = { version = "0.6.0", features = ["colored"] }
rand = { version = "0.8.4", features = ["small_rng"] }
simple_logger = "1.13.0"
dioxus-core-macro = { path = "../core-macro", version = "0.1.2" }
dioxus-hooks = { path = "../hooks" }
# dioxus-hooks = { path = "../hooks" }
criterion = "0.3.5"
[features]

View file

@ -2,7 +2,7 @@
This is the core crate for the Dioxus Virtual DOM. This README will focus on the technical design and layout of this Virtual DOM implementation. If you want to read more about using Dioxus, then check out the Dioxus crate, documentation, and website.
To build new apps with Dioxus or to extend the ecosystem with new hooks or components, use the `Dioxus` crate with the appropriate feature flags.
To build new apps with Dioxus or to extend the ecosystem with new hooks or components, use the higher-level `dioxus` crate with the appropriate feature flags.
## Internals
@ -10,69 +10,44 @@ Dioxus-core builds off the many frameworks that came before it. Notably, Dioxus
- React: hooks, concurrency, suspense
- Dodrio: bump allocation, double buffering, and some diffing architecture
- Percy: html! macro architecture, platform-agnostic edits
- InfernoJS: approach to keyed diffing
- Preact: approach for normalization and ref
- Yew: passion and inspiration ❤️
Dioxus-core leverages some really cool techniques and hits a very high level of parity with mature frameworks. However, Dioxus also brings some new unique features:
- managed lifetimes for borrowed data
- suspended nodes (task/fiber endpoints) for asynchronous vnodes
- placeholder approach for suspended vnodes
- fiber/interruptible diffing algorithm
- custom memory allocator for vnodes and all text content
- support for fragments w/ lazy normalization
- slab allocator for scopes
- mirrored-slab approach for remote vdoms
- dedicated subtrees for rendering into separate contexts from the same app
There's certainly more to the story, but these optimizations make Dioxus memory use and allocation count extremely minimal. For an average application, it is possible that zero allocations will need to be performed once the app has been mounted. Only when new components are added to the dom will allocations occur - and only en mass. The space of old VNodes is dynamically recycled as new nodes are added. Additionally, Dioxus tracks the average memory footprint of previous components to estimate how much memory allocate for future components.
There's certainly more to the story, but these optimizations make Dioxus memory use and allocation count extremely minimal. For an average application, it is possible that zero allocations will need to be performed once the app has been loaded. Only when new components are added to the dom will allocations occur. For a given component, the space of old VNodes is dynamically recycled as new nodes are added. Additionally, Dioxus tracks the average memory footprint of previous components to estimate how much memory allocate for future components.
All in all, Dioxus treats memory as an incredibly valuable resource. Combined with the memory-efficient footprint of Wasm compilation, Dioxus apps can scale to thousands of components and still stay snappy and respect your RAM usage.
All in all, Dioxus treats memory as a valuable resource. Combined with the memory-efficient footprint of Wasm compilation, Dioxus apps can scale to thousands of components and still stay snappy.
## Goals
We have big goals for Dioxus. The final implementation must:
The final implementation of Dioxus must:
- Be **fast**. Allocators are typically slow in Wasm/Rust, so we should have a smart way of allocating.
- Be extremely memory efficient. Servers should handle tens of thousands of simultaneous VDoms with no problem.
- Be concurrent. Components should be able to pause rendering using a threading mechanism.
- Be "remote". Edit lists should be separate from the Renderer implementation.
- Support SSR. VNodes should render to a string that can be served via a web server.
- Be memory efficient. Servers should handle tens of thousands of simultaneous VDoms with no problem.
- Be concurrent. Components should be able to pause rendering to let the screen paint the next frame.
- Be disconnected from a specific renderer (no WebSys dependency in the core crate).
- Support server-side-rendering (SSR). VNodes should render to a string that can be served via a web server.
- Be "live". Components should be able to be both server rendered and client rendered without needing frontend APIs.
- Be modular. Components and hooks should be work anywhere without worrying about target platform.
## Safety
Dioxus uses unsafe. The design of Dioxus *requires* unsafe (self-referential trees).
All of our test suite passes MIRI without errors.
Dioxus deals with arenas, lifetimes, asynchronous tasks, custom allocators, pinning, and a lot more foundational low-level work that is very difficult to implement with 0 unsafe.
If you don't want to use a crate that uses unsafe, then this crate is not for you.
however, we are always interested in decreasing the scope of the core VirtualDom to make it easier to review.
However, we are always interested in decreasing the scope of the core VirtualDom to make it easier to review. We'd be happy to welcome PRs that can eliminate unsafe code while still upholding the numerous variants required to execute certain features.
We'd also be happy to welcome PRs that can eliminate unsafe code while still upholding the numerous variants required to execute certain features.
There's a few invariants that are very important:
- References to `ScopeInner` and `Props` passed into components are *always* valid for as long as the component exists. Even if the scope backing is resized to fit more scopes, the scope has to stay the same place in memory.
## Suspense
Suspense is done through combinators on values.
```rust
let name = get_name(cx).suspend();
rsx!(
div {
{name}
div {
div {
}
}
}
)
```

View file

@ -1,5 +1,7 @@
# Dioxus Core Architecture:
This document is mostly a brain-dump on how things work. A lot of this information might be outdated. Certain features (priority queues, swim lanes) might not be implemented yet.
Main topics covered here:
- Fiber, Concurrency, and Cooperative Scheduling
- Suspense

View file

@ -23,7 +23,7 @@ criterion_group!(mbenches, create_rows);
criterion_main!(mbenches);
fn create_rows(c: &mut Criterion) {
static App: Component<()> = |cx, _| {
static App: Component<()> = |cx| {
let mut rng = SmallRng::from_entropy();
let rows = (0..10_000_usize).map(|f| {
let label = Label::new(&mut rng);
@ -53,11 +53,11 @@ struct RowProps {
row_id: usize,
label: Label,
}
fn Row(cx: Scope, props: &RowProps) -> Element {
let [adj, col, noun] = props.label.0;
fn Row(cx: Scope<RowProps>) -> Element {
let [adj, col, noun] = cx.props.label.0;
cx.render(rsx! {
tr {
td { class:"col-md-1", "{props.row_id}" }
td { class:"col-md-1", "{cx.props.row_id}" }
td { class:"col-md-1", onclick: move |_| { /* run onselect */ }
a { class: "lbl", "{adj}" "{col}" "{noun}" }
}

View file

@ -31,21 +31,3 @@ fn bleat() {
let blah = String::from("asd");
eat(&blah);
}
// struct Lower {}
// #[derive(Clone, Copy)]
// struct Upper {}
// impl std::ops::Deref for Upper {
// type Target = Lower;
// fn deref(&self) -> &Self::Target {
// todo!()
// }
// }
// fn mark(f: &Lower) {}
// fn bark() {
// let up = Upper {};
// mark(&up);
// }

View file

@ -1,16 +1,10 @@
use dioxus::prelude::*;
use dioxus_core as dioxus;
use dioxus_core_macro::*;
use dioxus_hooks::use_state;
use dioxus_html as dioxus_elements;
fn main() {}
fn App(cx: Scope<()>) -> Element {
let color = use_state(&cx, || "white");
cx.render(rsx!(
div { onclick: move |_| color.set("red"), "red" }
div { onclick: move |_| color.set("blue"), "blue" }
))
todo!()
}

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 38 KiB

View file

@ -58,7 +58,7 @@ impl<'a, const A: bool> FragmentBuilder<'a, A> {
/// cx.render(rsx!{
/// div {
/// h1 {"Title card"}
/// {props.children}
/// {cx.props.children}
/// }
/// })
/// }

View file

@ -440,7 +440,7 @@ impl<'bump> DiffState<'bump> {
let height = parent_scope.height + 1;
let subtree = parent_scope.subtree.get();
let parent_scope = unsafe { self.scopes.get_scope_raw(parent_idx) };
let parent_scope = self.scopes.get_scope_raw(parent_idx);
let caller = unsafe { std::mem::transmute(vcomponent.caller as *const _) };
let fc_ptr = vcomponent.user_fc;
@ -716,13 +716,12 @@ impl<'bump> DiffState<'bump> {
new.associated_scope.set(Some(scope_addr));
// make sure the component's caller function is up to date
let scope = unsafe {
self.scopes
.get_scope_mut(scope_addr)
.unwrap_or_else(|| panic!("could not find {:?}", scope_addr))
};
let scope = self
.scopes
.get_scope(scope_addr)
.unwrap_or_else(|| panic!("could not find {:?}", scope_addr));
scope.caller = unsafe { std::mem::transmute(new.caller) };
scope.caller.set(unsafe { std::mem::transmute(new.caller) });
// React doesn't automatically memoize, but we do.
let props_are_the_same = old.comparator.unwrap();

View file

@ -520,8 +520,8 @@ impl<'a> NodeFactory<'a> {
move |other: &VComponent| {
if user_fc == other.user_fc {
// Safety
// - We guarantee that FC<P> is the same by function pointer
// - Because FC<P> is the same, then P must be the same (even with generics)
// - We guarantee that Component<P> is the same by function pointer
// - Because Component<P> is the same, then P must be the same (even with generics)
// - Non-static P are autoderived to memoize as false
// - This comparator is only called on a corresponding set of bumpframes
//

View file

@ -28,7 +28,7 @@ use bumpalo::{boxed::Box as BumpBox, Bump};
/// }
///
/// fn Example(cx: Context, props: &ExampleProps) -> Element {
/// cx.render(rsx!{ div {"Hello, {props.name}"} })
/// cx.render(rsx!{ div {"Hello, {cx.props.name}"} })
/// }
/// ```
pub struct Scope<'a, P> {
@ -88,7 +88,7 @@ pub struct ScopeState {
pub(crate) frames: [BumpFrame; 2],
pub(crate) caller: *const dyn Fn(&ScopeState) -> Element,
pub(crate) caller: Cell<*const dyn Fn(&ScopeState) -> Element>,
pub(crate) items: RefCell<SelfReferentialItems<'static>>,
@ -269,12 +269,12 @@ impl ScopeState {
/// ```rust, ignore
/// struct SharedState(&'static str);
///
/// static App: FC<()> = |cx, props|{
/// static App: Component<()> = |cx, props|{
/// cx.use_hook(|_| cx.provide_state(SharedState("world")), |_| {}, |_| {});
/// rsx!(cx, Child {})
/// }
///
/// static Child: FC<()> = |cx, props| {
/// static Child: Component<()> = |cx| {
/// let state = cx.consume_state::<SharedState>();
/// rsx!(cx, div { "hello {state.0}" })
/// }
@ -344,7 +344,7 @@ impl ScopeState {
/// ## Example
///
/// ```ignore
/// fn Component(cx: Scope, props: &Props) -> Element {
/// fn Component(cx: Scope<Props>) -> Element {
/// // Lazy assemble the VNode tree
/// let lazy_nodes = rsx!("hello world");
///

View file

@ -72,14 +72,10 @@ impl ScopeArena {
unsafe { self.scopes.borrow().get(&id).map(|f| &**f) }
}
pub(crate) unsafe fn get_scope_raw(&self, id: ScopeId) -> Option<*mut ScopeState> {
pub(crate) fn get_scope_raw(&self, id: ScopeId) -> Option<*mut ScopeState> {
self.scopes.borrow().get(&id).copied()
}
pub(crate) unsafe fn get_scope_mut(&self, id: ScopeId) -> Option<&mut ScopeState> {
self.scopes.borrow().get(&id).map(|s| &mut **s)
}
pub(crate) fn new_with_key(
&self,
fc_ptr: *const (),
@ -95,35 +91,13 @@ impl ScopeArena {
if let Some(old_scope) = self.free_scopes.borrow_mut().pop() {
let scope = unsafe { &mut *old_scope };
scope.caller = caller;
scope.caller.set(caller);
scope.parent_scope = parent_scope;
scope.height = height;
scope.subtree = Cell::new(subtree);
scope.our_arena_idx = new_scope_id;
scope.container = container;
// scope.frames[0].nodes.get_mut().push({
// let vnode = scope.frames[0]
// .bump
// .alloc(VNode::Text(scope.frames[0].bump.alloc(VText {
// dom_id: Default::default(),
// is_static: false,
// text: "",
// })));
// unsafe { std::mem::transmute(vnode as *mut VNode) }
// });
// scope.frames[1].nodes.get_mut().push({
// let vnode = scope.frames[1]
// .bump
// .alloc(VNode::Text(scope.frames[1].bump.alloc(VText {
// dom_id: Default::default(),
// is_static: false,
// text: "",
// })));
// unsafe { std::mem::transmute(vnode as *mut VNode) }
// });
let any_item = self.scopes.borrow_mut().insert(new_scope_id, scope);
debug_assert!(any_item.is_none());
} else {
@ -148,7 +122,7 @@ impl ScopeArena {
subtree: Cell::new(subtree),
is_subtree_root: Cell::new(false),
caller,
caller: Cell::new(caller),
generation: 0.into(),
shared_contexts: Default::default(),
@ -277,18 +251,20 @@ impl ScopeArena {
// Remove all the outdated listeners
self.ensure_drop_safety(id);
let scope = unsafe { &mut *self.get_scope_mut(id).expect("could not find scope") };
// todo: we *know* that this is aliased by the contents of the scope itself
let scope = unsafe { &mut *self.get_scope_raw(id).expect("could not find scope") };
// Safety:
// - We dropped the listeners, so no more &mut T can be used while these are held
// - All children nodes that rely on &mut T are replaced with a new reference
scope.hook_idx.set(0);
// Safety:
// - We've dropped all references to the wip bump frame with "ensure_drop_safety"
unsafe { scope.reset_wip_frame() };
// book keeping to ensure safety around the borrowed data
{
// Safety:
// - We've dropped all references to the wip bump frame with "ensure_drop_safety"
unsafe { scope.reset_wip_frame() };
let mut items = scope.items.borrow_mut();
// just forget about our suspended nodes while we're at it
@ -298,12 +274,9 @@ impl ScopeArena {
debug_assert!(items.listeners.is_empty());
debug_assert!(items.borrowed_props.is_empty());
debug_assert!(items.tasks.is_empty());
// Todo: see if we can add stronger guarantees around internal bookkeeping and failed component renders.
// scope.wip_frame().nodes
}
let render: &dyn Fn(&ScopeState) -> Element = unsafe { &*scope.caller };
let render: &dyn Fn(&ScopeState) -> Element = unsafe { &*scope.caller.get() };
if let Some(node) = render(scope) {
if !scope.items.borrow().tasks.is_empty() {
@ -319,6 +292,10 @@ impl ScopeArena {
scope.cycle_frame();
true
} else {
// the component bailed out early
// this leaves the wip frame and all descendents in a state where
// their WIP frames are invalid
// todo: descendents should not cause the app to crash
false
}
}

View file

@ -25,7 +25,7 @@ use std::{any::Any, collections::VecDeque, pin::Pin, sync::Arc, task::Poll};
///
/// fn App(cx: Context, props: &AppProps) -> Element {
/// cx.render(rsx!(
/// div {"hello, {props.title}"}
/// div {"hello, {cx.props.title}"}
/// ))
/// }
/// ```
@ -36,7 +36,7 @@ use std::{any::Any, collections::VecDeque, pin::Pin, sync::Arc, task::Poll};
/// fn App(cx: Context, props: &AppProps) -> Element {
/// cx.render(rsx!(
/// NavBar { routes: ROUTES }
/// Title { "{props.title}" }
/// Title { "{cx.props.title}" }
/// Footer {}
/// ))
/// }
@ -459,7 +459,7 @@ impl VirtualDom {
///
/// # Example
/// ```rust, ignore
/// static App: FC<()> = |cx, props| cx.render(rsx!{ "hello world" });
/// static App: Component<()> = |cx, props| cx.render(rsx!{ "hello world" });
/// let mut dom = VirtualDom::new();
/// let edits = dom.rebuild();
///
@ -497,7 +497,7 @@ impl VirtualDom {
/// value: Shared<&'static str>,
/// }
///
/// static App: FC<AppProps> = |cx, props|{
/// static App: Component<AppProps> = |cx, props|{
/// let val = cx.value.borrow();
/// cx.render(rsx! { div { "{val}" } })
/// };

View file

@ -7,7 +7,6 @@ use dioxus_core::DomEdit::*;
use dioxus_core::ScopeId;
use dioxus_core_macro::*;
use dioxus_hooks::*;
use dioxus_html as dioxus_elements;
use std::sync::{Arc, Mutex};

View file

@ -4,11 +4,11 @@ This crate provides an ergonomic API for Dioxus to build desktop apps.
```rust
fn main() {
dioxus::desktop::launch(App, |c| c)
dioxus::desktop::launch(App)
}
static App: FC<()> = |cx, props| {
let (count, set_count) = use_state(cx, || 0);
static App: Component<()> = |cx| {
let (count, set_count) = use_state(&cx, || 0);
cx.render(rsx!(
WebviewWindow {
@ -34,7 +34,7 @@ Window management, system trays, notifications, and other desktop-related functi
Managing windows is done by simply rendering content into a `WebviewWindow` component.
```rust
static App: FC<()> = |cx, props| {
static App: Component<()> = |cx| {
rsx!(cx, WebviewWindow { "hello world" } )
}
```
@ -46,7 +46,7 @@ Notifications also use a declarative approach. Sending a notification has never
The api has been somewhat modeled after https://github.com/mikaelbr/node-notifier
```rust
static Notifications: FC<()> = |cx, props| {
static Notifications: Component<()> = |cx| {
cx.render(rsx!(
Notification {
title: "title"
@ -78,7 +78,7 @@ static Notifications: FC<()> = |cx, props| {
Dioxus Desktop supports app trays, which can be built with native menu groups or with a custom window.
```rust
static Tray: FC<()> = |cx, props| {
static Tray: Component<()> = |cx| {
cx.render(rsx!(
GlobalTray {
MenuGroup {
@ -90,7 +90,7 @@ static Tray: FC<()> = |cx, props| {
};
// using a builder
static Tray: FC<()> = |cx, props| {
static Tray: Component<()> = |cx| {
let menu = MenuGroup::builder(cx)
.with_items([
MenuGroupItem::builder()
@ -107,7 +107,7 @@ static Tray: FC<()> = |cx, props| {
}
// or with a custom window
static Tray: FC<()> = |cx, props| {
static Tray: Component<()> = |cx| {
rsx!(cx, GlobalTray { div { "custom buttons here" } })
};
```
@ -116,7 +116,7 @@ static Tray: FC<()> = |cx, props| {
Declaring menus is convenient and cross-platform.
```rust
static Menu: FC<()> = |cx, props| {
static Menu: Component<()> = |cx| {
cx.render(rsx!(
MenuBarMajorItem { title: "File"
MenuGroup {

View file

@ -12,11 +12,11 @@ use dioxus_html as dioxus_elements;
fn main() {
simple_logger::init().unwrap();
dioxus_desktop::launch(App, |c| c);
dioxus_desktop::launch(app);
}
static App: Component<()> = |cx, props| {
let mut count = use_state(cx, || 0);
fn app(cx: Scope<()>) -> Element {
let mut count = use_state(&cx, || 0);
log::debug!("count is {:?}", count);
cx.push_task(|| async move {

View file

@ -90,7 +90,7 @@ fn syntax_works() {
use dioxus_hooks::*;
use dioxus_html as dioxus_elements;
static App: FC<()> = |cx, props| {
static App: Component<()> = |cx| {
cx.render(rsx! {
// left window
WebviewWindow {

View file

@ -6,6 +6,9 @@
mod cfg;
mod escape;
mod events;
pub use wry;
pub use wry::application as tao;
// mod desktop_context;
use cfg::DesktopConfig;
@ -28,7 +31,10 @@ use wry::{
webview::{WebView, WebViewBuilder},
};
pub fn launch(
pub fn launch(root: Component<()>) {
launch_with_props(root, (), |c| c)
}
pub fn launch_cfg(
root: Component<()>,
config_builder: impl for<'a, 'b> FnOnce(&'b mut DesktopConfig<'a>) -> &'b mut DesktopConfig<'a>,
) {

View file

@ -1,11 +1,10 @@
[package]
name = "dioxus-hooks"
version = "0.0.0"
version = "0.1.3"
authors = ["Jonathan Kelley <jkelleyrtp@gmail.com>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
dioxus-core = { path = "../../packages/core", version = "0.1.3" }
futures = "0.3"
dioxus-core = { path = "../../packages/core" }

View file

@ -16,10 +16,10 @@ You can always use it "normally" with the `split` method:
```rust
// Normal usage:
let value = use_state(cx, || 10);
let value = use_state(&cx, || 10);
// "Classic" usage:
let (value, set_value) = use_state(cx, || 0).split();
let (value, set_value) = use_state(&cx, || 0).split();
```
## use_ref

View file

@ -1,9 +1,6 @@
mod usestate;
pub use usestate::{use_state, AsyncUseState, UseState};
mod usestate2;
// pub use usestate2::use_state2;
mod useref;
pub use useref::*;

Some files were not shown because too many files have changed in this diff Show more