Merge branch 'upstream' into optimize-templates-v3
This commit is contained in:
commit
99a4a9d45b
113 files changed
+336
-817
No files matched your search
@@ -13,7 +13,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
environment: docs
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
# NOTE: Comment out when https://github.com/rust-lang/mdBook/pull/1306 is merged and released
|
||||
# - name: Setup mdBook
|
||||
@@ -32,7 +32,7 @@ jobs:
|
||||
cd router && mdbook build -d ../nightly/router && cd ..
|
||||
|
||||
- name: Deploy 🚀
|
||||
uses: JamesIves/github-pages-deploy-action@v4.2.3
|
||||
uses: JamesIves/github-pages-deploy-action@v4.4.1
|
||||
with:
|
||||
branch: gh-pages # The branch the action should deploy to.
|
||||
folder: docs/nightly # The folder the action should deploy.
|
||||
|
||||
@@ -30,7 +30,7 @@ jobs:
|
||||
name: Test Suite
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
|
||||
@@ -32,7 +32,7 @@ jobs:
|
||||
name: Check
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
@@ -51,7 +51,7 @@ jobs:
|
||||
name: Test Suite
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
@@ -73,7 +73,7 @@ jobs:
|
||||
name: Rustfmt
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
@@ -91,7 +91,7 @@ jobs:
|
||||
name: Clippy
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
@@ -115,7 +115,7 @@ jobs:
|
||||
# options: --security-opt seccomp=unconfined
|
||||
# steps:
|
||||
# - name: Checkout repository
|
||||
# uses: actions/checkout@v2
|
||||
# uses: actions/checkout@v3
|
||||
# - name: Generate code coverage
|
||||
# run: |
|
||||
# apt-get update &&\
|
||||
|
||||
@@ -48,7 +48,7 @@ jobs:
|
||||
- name: disable git eol translation
|
||||
run: git config --global core.autocrlf false
|
||||
- name: checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
|
||||
# Run build
|
||||
- name: Install Rustup using win.rustup.rs
|
||||
|
||||
+1
-6
@@ -16,11 +16,6 @@ members = [
|
||||
"packages/autofmt",
|
||||
"packages/rsx",
|
||||
"docs/guide",
|
||||
# "packages/tui",
|
||||
# "packages/native-core",
|
||||
# "packages/native-core-macro",
|
||||
]
|
||||
exclude = [
|
||||
"packages/tui",
|
||||
"packages/native-core",
|
||||
"packages/native-core-macro",
|
||||
@@ -40,7 +35,7 @@ homepage = "https://dioxuslabs.com"
|
||||
documentation = "https://dioxuslabs.com"
|
||||
keywords = ["dom", "ui", "gui", "react", "wasm"]
|
||||
rust-version = "1.60.0"
|
||||
|
||||
publish = false
|
||||
|
||||
[dev-dependencies]
|
||||
dioxus = { path = "./packages/dioxus" }
|
||||
|
||||
@@ -54,7 +54,7 @@ Dioxus is a portable, performant, and ergonomic framework for building cross-pla
|
||||
|
||||
```rust
|
||||
fn app(cx: Scope) -> Element {
|
||||
let mut count = use_state(&cx, || 0);
|
||||
let mut count = use_state(cx, || 0);
|
||||
|
||||
cx.render(rsx! {
|
||||
h1 { "High-Five counter: {count}" }
|
||||
|
||||
@@ -26,7 +26,7 @@ struct ClickableProps<'a> {
|
||||
// ANCHOR: Clickable
|
||||
fn Clickable<'a>(cx: Scope<'a, ClickableProps<'a>>) -> Element {
|
||||
match cx.props.children {
|
||||
Some(VNode::Text(_)) => {
|
||||
Ok(VNode { dynamic_nodes, .. }) => {
|
||||
todo!("render some stuff")
|
||||
}
|
||||
_ => {
|
||||
|
||||
@@ -6,7 +6,7 @@ fn main() {
|
||||
}
|
||||
|
||||
pub fn App(cx: Scope) -> Element {
|
||||
let is_logged_in = use_state(&cx, || false);
|
||||
let is_logged_in = use_state(cx, || false);
|
||||
|
||||
cx.render(rsx!(LogIn {
|
||||
is_logged_in: **is_logged_in,
|
||||
@@ -48,7 +48,7 @@ fn LogIn<'a>(
|
||||
fn LogInWarning(cx: Scope, is_logged_in: bool) -> Element {
|
||||
// ANCHOR: conditional_none
|
||||
if *is_logged_in {
|
||||
return None;
|
||||
return cx.render(rsx!(()));
|
||||
}
|
||||
|
||||
cx.render(rsx! {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
use dioxus::events::MouseData;
|
||||
use dioxus::prelude::*;
|
||||
|
||||
fn main() {
|
||||
@@ -20,7 +19,7 @@ fn App(cx: Scope) -> Element {
|
||||
// ANCHOR: component_with_handler
|
||||
#[derive(Props)]
|
||||
pub struct FancyButtonProps<'a> {
|
||||
on_click: EventHandler<'a, MouseData>,
|
||||
on_click: EventHandler<'a, MouseEvent>,
|
||||
}
|
||||
|
||||
pub fn FancyButton<'a>(cx: Scope<'a, FancyButtonProps<'a>>) -> Element<'a> {
|
||||
|
||||
@@ -14,7 +14,7 @@ fn App(cx: Scope) -> Element {
|
||||
button {
|
||||
onclick: move |event| {
|
||||
// now, outer won't be triggered
|
||||
event.cancel_bubble();
|
||||
event.stop_propogation();
|
||||
},
|
||||
"inner"
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ fn App(cx: Scope) -> Element {
|
||||
background_color: "red",
|
||||
justify_content: "center",
|
||||
align_items: "center",
|
||||
onkeydown: move |k: KeyboardEvent| if let KeyCode::Q = k.data.key_code {
|
||||
onkeydown: move |k: KeyboardEvent| if let KeyCode::Q = k.key_code {
|
||||
tui_ctx.quit();
|
||||
},
|
||||
|
||||
|
||||
@@ -17,13 +17,13 @@ fn App(cx: Scope) -> Element {
|
||||
// But `if` statements only run if the conditional is true!
|
||||
// So we might violate rule 2.
|
||||
if you_are_happy && you_know_it {
|
||||
let something = use_state(&cx, || "hands");
|
||||
let something = use_state(cx, || "hands");
|
||||
println!("clap your {something}")
|
||||
}
|
||||
|
||||
// ✅ instead, *always* call use_state
|
||||
// You can put other stuff in the conditional though
|
||||
let something = use_state(&cx, || "hands");
|
||||
let something = use_state(cx, || "hands");
|
||||
if you_are_happy && you_know_it {
|
||||
println!("clap your {something}")
|
||||
}
|
||||
@@ -33,12 +33,12 @@ fn App(cx: Scope) -> Element {
|
||||
// ❌ don't call hooks inside closures!
|
||||
// We can't guarantee that the closure, if used, will be called at the same time every time
|
||||
let _a = || {
|
||||
let b = use_state(&cx, || 0);
|
||||
let b = use_state(cx, || 0);
|
||||
b.get()
|
||||
};
|
||||
|
||||
// ✅ instead, move hook `b` outside
|
||||
let b = use_state(&cx, || 0);
|
||||
let b = use_state(cx, || 0);
|
||||
let _a = || b.get();
|
||||
// ANCHOR_END: closure
|
||||
|
||||
@@ -50,12 +50,12 @@ fn App(cx: Scope) -> Element {
|
||||
// ❌ Do not use hooks in loops!
|
||||
// In this case, if the length of the Vec changes, we break rule 2
|
||||
for _name in &names {
|
||||
let is_selected = use_state(&cx, || false);
|
||||
let is_selected = use_state(cx, || false);
|
||||
println!("selected: {is_selected}");
|
||||
}
|
||||
|
||||
// ✅ Instead, use a hashmap with use_ref
|
||||
let selection_map = use_ref(&cx, HashMap::<&str, bool>::new);
|
||||
let selection_map = use_ref(cx, HashMap::<&str, bool>::new);
|
||||
|
||||
for name in &names {
|
||||
let is_selected = selection_map.read()[name];
|
||||
@@ -63,5 +63,5 @@ fn App(cx: Scope) -> Element {
|
||||
}
|
||||
// ANCHOR_END: loop
|
||||
|
||||
None
|
||||
cx.render(rsx!(()))
|
||||
}
|
||||
@@ -8,6 +8,6 @@ struct AppSettings {}
|
||||
|
||||
// ANCHOR: wrap_context
|
||||
fn use_settings(cx: &ScopeState) -> UseSharedState<AppSettings> {
|
||||
use_context::<AppSettings>(cx).expect("App settings not provided")
|
||||
use_shared_state::<AppSettings>(cx).expect("App settings not provided")
|
||||
}
|
||||
// ANCHOR_END: wrap_context
|
||||
@@ -7,7 +7,7 @@ fn main() {
|
||||
|
||||
// ANCHOR: component
|
||||
fn App(cx: Scope) -> Element {
|
||||
let mut count = use_state(&cx, || 0);
|
||||
let mut count = use_state(cx, || 0);
|
||||
|
||||
cx.render(rsx!(
|
||||
h1 { "High-Five counter: {count}" }
|
||||
|
||||
@@ -8,8 +8,8 @@ fn main() {
|
||||
// ANCHOR: component
|
||||
fn App(cx: Scope) -> Element {
|
||||
// ANCHOR: use_state_calls
|
||||
let mut count_a = use_state(&cx, || 0);
|
||||
let mut count_b = use_state(&cx, || 0);
|
||||
let mut count_a = use_state(cx, || 0);
|
||||
let mut count_b = use_state(cx, || 0);
|
||||
// ANCHOR_END: use_state_calls
|
||||
|
||||
cx.render(rsx!(
|
||||
|
||||
@@ -7,7 +7,7 @@ fn main() {
|
||||
|
||||
// ANCHOR: component
|
||||
fn App(cx: Scope) -> Element {
|
||||
let list = use_ref(&cx, Vec::new);
|
||||
let list = use_ref(cx, Vec::new);
|
||||
let list_formatted = format!("{:?}", *list.read());
|
||||
|
||||
cx.render(rsx!(
|
||||
|
||||
@@ -7,7 +7,7 @@ fn main() {
|
||||
|
||||
// ANCHOR: component
|
||||
fn App(cx: Scope) -> Element {
|
||||
let name = use_state(&cx, || "bob".to_string());
|
||||
let name = use_state(cx, || "bob".to_string());
|
||||
|
||||
cx.render(rsx! {
|
||||
input {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// ANCHOR: all
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
use dioxus::events::FormData;
|
||||
use dioxus::prelude::*;
|
||||
|
||||
fn main() {
|
||||
@@ -18,7 +17,7 @@ fn MemeEditor(cx: Scope) -> Element {
|
||||
width: fit-content;
|
||||
";
|
||||
|
||||
let caption = use_state(&cx, || "me waiting for my rust code to compile".to_string());
|
||||
let caption = use_state(cx, || "me waiting for my rust code to compile".to_string());
|
||||
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
@@ -83,7 +82,7 @@ fn Meme<'a>(cx: Scope<'a>, caption: &'a str) -> Element<'a> {
|
||||
fn CaptionEditor<'a>(
|
||||
cx: Scope<'a>,
|
||||
caption: &'a str,
|
||||
on_input: EventHandler<'a, FormData>,
|
||||
on_input: EventHandler<'a, FormEvent>,
|
||||
) -> Element<'a> {
|
||||
let input_style = r"
|
||||
border: none;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// ANCHOR: all
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
use dioxus::events::FormData;
|
||||
use dioxus::prelude::*;
|
||||
|
||||
fn main() {
|
||||
@@ -14,10 +13,10 @@ struct DarkMode(bool);
|
||||
|
||||
pub fn App(cx: Scope) -> Element {
|
||||
// ANCHOR: context_provider
|
||||
use_context_provider(&cx, || DarkMode(false));
|
||||
use_shared_state_provider(cx, || DarkMode(false));
|
||||
// ANCHOR_END: context_provider
|
||||
|
||||
let is_dark_mode = use_is_dark_mode(&cx);
|
||||
let is_dark_mode = use_is_dark_mode(cx);
|
||||
|
||||
let wrapper_style = if is_dark_mode {
|
||||
r"
|
||||
@@ -37,7 +36,7 @@ pub fn App(cx: Scope) -> Element {
|
||||
|
||||
pub fn use_is_dark_mode(cx: &ScopeState) -> bool {
|
||||
// ANCHOR: use_context
|
||||
let dark_mode_context = use_context::<DarkMode>(cx);
|
||||
let dark_mode_context = use_shared_state::<DarkMode>(cx);
|
||||
// ANCHOR_END: use_context
|
||||
|
||||
dark_mode_context
|
||||
@@ -47,7 +46,7 @@ pub fn use_is_dark_mode(cx: &ScopeState) -> bool {
|
||||
|
||||
// ANCHOR: toggle
|
||||
pub fn DarkModeToggle(cx: Scope) -> Element {
|
||||
let dark_mode = use_context::<DarkMode>(&cx)?;
|
||||
let dark_mode = use_shared_state::<DarkMode>(cx).unwrap();
|
||||
|
||||
let style = if dark_mode.read().0 {
|
||||
"color:white"
|
||||
@@ -71,7 +70,7 @@ pub fn DarkModeToggle(cx: Scope) -> Element {
|
||||
|
||||
// ANCHOR: meme_editor
|
||||
fn MemeEditor(cx: Scope) -> Element {
|
||||
let is_dark_mode = use_is_dark_mode(&cx);
|
||||
let is_dark_mode = use_is_dark_mode(cx);
|
||||
let heading_style = if is_dark_mode { "color: white" } else { "" };
|
||||
|
||||
let container_style = r"
|
||||
@@ -82,7 +81,7 @@ fn MemeEditor(cx: Scope) -> Element {
|
||||
width: fit-content;
|
||||
";
|
||||
|
||||
let caption = use_state(&cx, || "me waiting for my rust code to compile".to_string());
|
||||
let caption = use_state(cx, || "me waiting for my rust code to compile".to_string());
|
||||
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
@@ -150,9 +149,9 @@ fn Meme<'a>(cx: Scope<'a>, caption: &'a str) -> Element<'a> {
|
||||
fn CaptionEditor<'a>(
|
||||
cx: Scope<'a>,
|
||||
caption: &'a str,
|
||||
on_input: EventHandler<'a, FormData>,
|
||||
on_input: EventHandler<'a, FormEvent>,
|
||||
) -> Element<'a> {
|
||||
let is_dark_mode = use_is_dark_mode(&cx);
|
||||
let is_dark_mode = use_is_dark_mode(cx);
|
||||
|
||||
let colors = if is_dark_mode {
|
||||
r"
|
||||
|
||||
@@ -14,9 +14,9 @@ struct Comment {
|
||||
|
||||
pub fn App(cx: Scope) -> Element {
|
||||
// ANCHOR: render_list
|
||||
let comment_field = use_state(&cx, String::new);
|
||||
let mut next_id = use_state(&cx, || 0);
|
||||
let comments = use_ref(&cx, Vec::<Comment>::new);
|
||||
let comment_field = use_state(cx, String::new);
|
||||
let mut next_id = use_state(cx, || 0);
|
||||
let comments = use_ref(cx, Vec::<Comment>::new);
|
||||
|
||||
let comments_lock = comments.read();
|
||||
let comments_rendered = comments_lock.iter().map(|comment| {
|
||||
|
||||
@@ -103,7 +103,7 @@ pub fn Expression(cx: Scope) -> Element {
|
||||
// ANCHOR: expression
|
||||
let text = "Dioxus";
|
||||
cx.render(rsx!(span {
|
||||
[text.to_uppercase()]
|
||||
text.to_uppercase()
|
||||
}))
|
||||
// ANCHOR_END: expression
|
||||
}
|
||||
@@ -8,7 +8,7 @@ fn main() {
|
||||
|
||||
fn App(cx: Scope) -> Element {
|
||||
// ANCHOR: spawn
|
||||
let logged_in = use_state(&cx, || false);
|
||||
let logged_in = use_state(cx, || false);
|
||||
|
||||
let log_in = move |_| {
|
||||
cx.spawn({
|
||||
@@ -58,18 +58,18 @@ pub fn Tokio(cx: Scope) -> Element {
|
||||
// ANCHOR_END: tokio
|
||||
};
|
||||
|
||||
None
|
||||
cx.render(rsx!(()))
|
||||
}
|
||||
|
||||
pub fn ToOwnedMacro(cx: Scope) -> Element {
|
||||
let count = use_state(&cx, || 0);
|
||||
let age = use_state(&cx, || 0);
|
||||
let name = use_state(&cx, || 0);
|
||||
let description = use_state(&cx, || 0);
|
||||
let count = use_state(cx, || 0);
|
||||
let age = use_state(cx, || 0);
|
||||
let name = use_state(cx, || 0);
|
||||
let description = use_state(cx, || 0);
|
||||
|
||||
let _ = || {
|
||||
// ANCHOR: to_owned_macro
|
||||
use dioxus::core::to_owned;
|
||||
use dioxus::hooks::to_owned;
|
||||
|
||||
cx.spawn({
|
||||
to_owned![count, age, name, description];
|
||||
@@ -80,5 +80,5 @@ pub fn ToOwnedMacro(cx: Scope) -> Element {
|
||||
// ANCHOR_END: to_owned_macro
|
||||
};
|
||||
|
||||
None
|
||||
cx.render(rsx!(()))
|
||||
}
|
||||
@@ -14,7 +14,7 @@ struct ApiResponse {
|
||||
|
||||
fn App(cx: Scope) -> Element {
|
||||
// ANCHOR: use_future
|
||||
let future = use_future(&cx, (), |_| async move {
|
||||
let future = use_future(cx, (), |_| async move {
|
||||
reqwest::get("https://dog.ceo/api/breeds/image/random")
|
||||
.await
|
||||
.unwrap()
|
||||
@@ -47,7 +47,7 @@ fn App(cx: Scope) -> Element {
|
||||
#[inline_props]
|
||||
fn RandomDog(cx: Scope, breed: String) -> Element {
|
||||
// ANCHOR: dependency
|
||||
let future = use_future(&cx, (breed,), |(breed,)| async move {
|
||||
let future = use_future(cx, (breed,), |(breed,)| async move {
|
||||
reqwest::get(format!("https://dog.ceo/api/breed/{breed}/images/random"))
|
||||
.await
|
||||
.unwrap()
|
||||
@@ -56,5 +56,5 @@ fn RandomDog(cx: Scope, breed: String) -> Element {
|
||||
});
|
||||
// ANCHOR_END: dependency
|
||||
|
||||
None
|
||||
cx.render(rsx!(()))
|
||||
}
|
||||
@@ -12,7 +12,7 @@ Your component today might look something like this:
|
||||
|
||||
```rust
|
||||
fn Comp(cx: Scope) -> 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
|
||||
|
||||
```rust
|
||||
fn Comp(cx: Scope) -> 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 {
|
||||
@@ -49,7 +49,7 @@ We can use signals to generate a two-way binding between data and the input box.
|
||||
|
||||
```rust
|
||||
fn Comp(cx: Scope) -> DomTree {
|
||||
let mut title = use_signal(&cx, || String::from("Title"));
|
||||
let mut title = use_signal(cx, || String::from("Title"));
|
||||
cx.render(rsx!(input { value: title }))
|
||||
}
|
||||
```
|
||||
@@ -58,8 +58,8 @@ For a slightly more interesting example, this component calculates the sum betwe
|
||||
|
||||
```rust
|
||||
fn Calculator(cx: Scope) -> DomTree {
|
||||
let mut a = use_signal(&cx, || 0);
|
||||
let mut b = use_signal(&cx, || 0);
|
||||
let mut a = use_signal(cx, || 0);
|
||||
let mut b = use_signal(cx, || 0);
|
||||
let mut c = a + b;
|
||||
rsx! {
|
||||
input { value: a }
|
||||
@@ -72,8 +72,8 @@ fn Calculator(cx: Scope) -> DomTree {
|
||||
Do you notice how we can use built-in operations on signals? Under the hood, we actually create a new derived signal that depends on `a` and `b`. Whenever `a` or `b` update, then `c` will update. If we need to create a new derived signal that's more complex than a basic operation (`std::ops`) we can either chain signals together or combine them:
|
||||
|
||||
```rust
|
||||
let mut a = use_signal(&cx, || 0);
|
||||
let mut b = use_signal(&cx, || 0);
|
||||
let mut a = use_signal(cx, || 0);
|
||||
let mut b = use_signal(cx, || 0);
|
||||
|
||||
// Chain signals together using the `with` method
|
||||
let c = a.with(b).map(|(a, b)| *a + *b);
|
||||
@@ -84,7 +84,7 @@ let c = a.with(b).map(|(a, b)| *a + *b);
|
||||
If we ever need to get the value out of a signal, we can simply `deref` it.
|
||||
|
||||
```rust
|
||||
let mut a = use_signal(&cx, || 0);
|
||||
let mut a = use_signal(cx, || 0);
|
||||
let c = *a + *b;
|
||||
```
|
||||
|
||||
@@ -97,7 +97,7 @@ Sometimes you want a signal to propagate across your app, either through far-awa
|
||||
```rust
|
||||
const TITLE: Atom<String> = || "".to_string();
|
||||
const Provider: Component = |cx|{
|
||||
let title = use_signal(&cx, &TITLE);
|
||||
let title = use_signal(cx, &TITLE);
|
||||
render!(input { value: title })
|
||||
};
|
||||
```
|
||||
@@ -106,7 +106,7 @@ If we use the `TITLE` atom in another component, we can cause updates to flow be
|
||||
|
||||
```rust
|
||||
const Receiver: Component = |cx|{
|
||||
let title = use_signal(&cx, &TITLE);
|
||||
let title = use_signal(cx, &TITLE);
|
||||
log::info!("This will only be called once!");
|
||||
rsx!(cx,
|
||||
div {
|
||||
@@ -133,7 +133,7 @@ Dioxus automatically understands how to use your signals when mixed with iterato
|
||||
```rust
|
||||
const DICT: AtomFamily<String, String> = |_| {};
|
||||
const List: Component = |cx|{
|
||||
let dict = use_signal(&cx, &DICT);
|
||||
let dict = use_signal(cx, &DICT);
|
||||
cx.render(rsx!(
|
||||
ul {
|
||||
For { each: dict, map: |k, v| rsx!( li { "{v}" }) }
|
||||
|
||||
@@ -59,7 +59,7 @@ If we represented the reactive graph presented above in Dioxus, it would look ve
|
||||
// Declare a component that holds our datasources and calculates `g`
|
||||
fn RenderGraph(cx: Scope) -> Element {
|
||||
let seconds = use_datasource(SECONDS);
|
||||
let constant = use_state(&cx, || 1);
|
||||
let constant = use_state(cx, || 1);
|
||||
|
||||
cx.render(rsx!(
|
||||
RenderG { seconds: seconds }
|
||||
|
||||
@@ -28,8 +28,8 @@ If we used global state like use_context or fermi, we might be tempted to inject
|
||||
|
||||
```rust
|
||||
fn Titlebar(cx: Scope<TitlebarProps>) -> Element {
|
||||
let title = use_read(&cx, TITLE);
|
||||
let subtitle = use_read(&cx, SUBTITLE);
|
||||
let title = use_read(cx, TITLE);
|
||||
let subtitle = use_read(cx, SUBTITLE);
|
||||
|
||||
cx.render(rsx!{/* ui */})
|
||||
}
|
||||
@@ -43,11 +43,11 @@ To enable our titlebar component to be used across apps, we want to lift our ato
|
||||
|
||||
```rust
|
||||
fn DocsiteTitlesection(cx: Scope) {
|
||||
let title = use_read(&cx, TITLE);
|
||||
let subtitle = use_read(&cx, SUBTITLE);
|
||||
let title = use_read(cx, TITLE);
|
||||
let subtitle = use_read(cx, SUBTITLE);
|
||||
|
||||
let username = use_read(&cx, USERNAME);
|
||||
let points = use_read(&cx, POINTS);
|
||||
let username = use_read(cx, USERNAME);
|
||||
let points = use_read(cx, POINTS);
|
||||
|
||||
cx.render(rsx!{
|
||||
TitleBar { title: title, subtitle: subtitle }
|
||||
|
||||
@@ -13,7 +13,7 @@ struct Todo {
|
||||
is_editing: bool,
|
||||
}
|
||||
|
||||
let todos = use_ref(&cx, || vec![Todo::new()]);
|
||||
let todos = use_ref(cx, || vec![Todo::new()]);
|
||||
|
||||
cx.render(rsx!{
|
||||
ul {
|
||||
@@ -40,7 +40,7 @@ Instead, let's refactor our Todo component to handle its own state:
|
||||
```rust
|
||||
#[inline_props]
|
||||
fn Todo<'a>(cx: Scope, todo: &'a Todo) -> Element {
|
||||
let is_hovered = use_state(&cx, || false);
|
||||
let is_hovered = use_state(cx, || false);
|
||||
|
||||
cx.render(rsx!{
|
||||
li {
|
||||
@@ -80,15 +80,15 @@ struct State {
|
||||
}
|
||||
|
||||
// in the component
|
||||
let state = use_ref(&cx, State::new)
|
||||
let state = use_ref(cx, State::new)
|
||||
```
|
||||
|
||||
The "better" approach for this particular component would be to break the state apart into different values:
|
||||
|
||||
```rust
|
||||
let count = use_state(&cx, || 0);
|
||||
let color = use_state(&cx, || "red");
|
||||
let names = use_state(&cx, HashMap::new);
|
||||
let count = use_state(cx, || 0);
|
||||
let color = use_state(cx, || "red");
|
||||
let names = use_state(cx, HashMap::new);
|
||||
```
|
||||
|
||||
You might recognize that our "names" value is a HashMap – which is not terribly cheap to clone every time we update its value. To solve this issue, we *highly* suggest using a library like [`im`](https://crates.io/crates/im) which will take advantage of structural sharing to make clones and mutations much cheaper.
|
||||
@@ -96,7 +96,7 @@ You might recognize that our "names" value is a HashMap – which is not terribl
|
||||
When combined with the `make_mut` method on `use_state`, you can get really succinct updates to collections:
|
||||
|
||||
```rust
|
||||
let todos = use_state(&cx, im_rc::HashMap::default);
|
||||
let todos = use_state(cx, im_rc::HashMap::default);
|
||||
|
||||
todos.make_mut().insert("new todo", Todo {
|
||||
contents: "go get groceries",
|
||||
|
||||
@@ -8,8 +8,8 @@ For example, let's say we have a component that has two children:
|
||||
```rust
|
||||
fn Demo(cx: Scope) -> Element {
|
||||
// don't worry about these 2, we'll cover them later
|
||||
let name = use_state(&cx, || String::from("bob"));
|
||||
let age = use_state(&cx, || 21);
|
||||
let name = use_state(cx, || String::from("bob"));
|
||||
let age = use_state(cx, || 21);
|
||||
|
||||
cx.render(rsx!{
|
||||
Name { name: name }
|
||||
|
||||
@@ -20,7 +20,7 @@ Our component is really simple – we just call `use_ref` to get an initial calc
|
||||
|
||||
```rust
|
||||
fn app(cx: Scope) -> Element {
|
||||
let state = use_ref(&cx, Calculator::new);
|
||||
let state = use_ref(cx, Calculator::new);
|
||||
|
||||
cx.render(rsx!{
|
||||
// the rendering code
|
||||
|
||||
@@ -10,7 +10,7 @@ The basic setup for coroutines is the `use_coroutine` hook. Most coroutines we w
|
||||
|
||||
```rust
|
||||
fn app(cx: Scope) -> Element {
|
||||
let ws: &UseCoroutine<()> = use_coroutine(&cx, |rx| async move {
|
||||
let ws: &UseCoroutine<()> = use_coroutine(cx, |rx| async move {
|
||||
// Connect to some sort of service
|
||||
let mut conn = connect_to_ws_server().await;
|
||||
|
||||
@@ -27,7 +27,7 @@ For many services, a simple async loop will handle the majority of use cases.
|
||||
However, if we want to temporarily disable the coroutine, we can "pause" it using the `pause` method, and "resume" it using the `resume` method:
|
||||
|
||||
```rust
|
||||
let sync: &UseCoroutine<()> = use_coroutine(&cx, |rx| async move {
|
||||
let sync: &UseCoroutine<()> = use_coroutine(cx, |rx| async move {
|
||||
// code for syncing
|
||||
});
|
||||
|
||||
@@ -63,7 +63,7 @@ enum ProfileUpdate {
|
||||
SetAge(i32)
|
||||
}
|
||||
|
||||
let profile = use_coroutine(&cx, |mut rx: UnboundedReciver<ProfileUpdate>| async move {
|
||||
let profile = use_coroutine(cx, |mut rx: UnboundedReciver<ProfileUpdate>| async move {
|
||||
let mut server = connect_to_server().await;
|
||||
|
||||
while let Ok(msg) = rx.next().await {
|
||||
@@ -86,9 +86,9 @@ cx.render(rsx!{
|
||||
For sufficiently complex apps, we could build a bunch of different useful "services" that loop on channels to update the app.
|
||||
|
||||
```rust
|
||||
let profile = use_coroutine(&cx, profile_service);
|
||||
let editor = use_coroutine(&cx, editor_service);
|
||||
let sync = use_coroutine(&cx, sync_service);
|
||||
let profile = use_coroutine(cx, profile_service);
|
||||
let editor = use_coroutine(cx, editor_service);
|
||||
let sync = use_coroutine(cx, sync_service);
|
||||
|
||||
async fn profile_service(rx: UnboundedReceiver<ProfileCommand>) {
|
||||
// do stuff
|
||||
@@ -109,9 +109,9 @@ We can combine coroutines with Fermi to emulate Redux Toolkit's Thunk system wit
|
||||
static USERNAME: Atom<String> = |_| "default".to_string();
|
||||
|
||||
fn app(cx: Scope) -> Element {
|
||||
let atoms = use_atom_root(&cx);
|
||||
let atoms = use_atom_root(cx);
|
||||
|
||||
use_coroutine(&cx, |rx| sync_service(rx, atoms.clone()));
|
||||
use_coroutine(cx, |rx| sync_service(rx, atoms.clone()));
|
||||
|
||||
cx.render(rsx!{
|
||||
Banner {}
|
||||
@@ -119,7 +119,7 @@ fn app(cx: Scope) -> Element {
|
||||
}
|
||||
|
||||
fn Banner(cx: Scope) -> Element {
|
||||
let username = use_read(&cx, USERNAME);
|
||||
let username = use_read(cx, USERNAME);
|
||||
|
||||
cx.render(rsx!{
|
||||
h1 { "Welcome back, {username}" }
|
||||
@@ -158,8 +158,8 @@ To yield values from a coroutine, simply bring in a `UseState` handle and set th
|
||||
|
||||
|
||||
```rust
|
||||
let sync_status = use_state(&cx, || Status::Launching);
|
||||
let sync_task = use_coroutine(&cx, |rx: UnboundedReceiver<SyncAction>| {
|
||||
let sync_status = use_state(cx, || Status::Launching);
|
||||
let sync_task = use_coroutine(cx, |rx: UnboundedReceiver<SyncAction>| {
|
||||
to_owned![sync_status];
|
||||
async move {
|
||||
loop {
|
||||
@@ -176,7 +176,7 @@ Coroutine handles are automatically injected through the context API. `use_corou
|
||||
|
||||
```rust
|
||||
fn Child(cx: Scope) -> Element {
|
||||
let sync_task = use_coroutine_handle::<SyncAction>(&cx);
|
||||
let sync_task = use_coroutine_handle::<SyncAction>(cx);
|
||||
|
||||
sync_task.send(SyncAction::SetUsername);
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ The next "best" way of handling errors in Dioxus is to match on the error locall
|
||||
To do this, we simply have an error state built into our component:
|
||||
|
||||
```rust
|
||||
let err = use_state(&cx, || None);
|
||||
let err = use_state(cx, || None);
|
||||
```
|
||||
|
||||
Whenever we perform an action that generates an error, we'll set that error state. We can then match on the error in a number of ways (early return, return Element, etc).
|
||||
@@ -64,7 +64,7 @@ Whenever we perform an action that generates an error, we'll set that error stat
|
||||
|
||||
```rust
|
||||
fn Commandline(cx: Scope) -> Element {
|
||||
let error = use_state(&cx, || None);
|
||||
let error = use_state(cx, || None);
|
||||
|
||||
cx.render(match *error {
|
||||
Some(error) => rsx!(
|
||||
@@ -85,7 +85,7 @@ If you're dealing with a handful of components with minimal nesting, you can jus
|
||||
|
||||
```rust
|
||||
fn Commandline(cx: Scope) -> Element {
|
||||
let error = use_state(&cx, || None);
|
||||
let error = use_state(cx, || None);
|
||||
|
||||
if let Some(error) = **error {
|
||||
return cx.render(rsx!{ "An error occured" });
|
||||
@@ -125,7 +125,7 @@ Then, in our top level component, we want to explicitly handle the possible erro
|
||||
|
||||
```rust
|
||||
fn TopLevel(cx: Scope) -> Element {
|
||||
let error = use_read(&cx, INPUT_ERROR);
|
||||
let error = use_read(cx, INPUT_ERROR);
|
||||
|
||||
match error {
|
||||
TooLong => return cx.render(rsx!{ "FAILED: Too long!" }),
|
||||
@@ -139,7 +139,7 @@ Now, whenever a downstream component has an error in its actions, it can simply
|
||||
|
||||
```rust
|
||||
fn Commandline(cx: Scope) -> Element {
|
||||
let set_error = use_set(&cx, INPUT_ERROR);
|
||||
let set_error = use_set(cx, INPUT_ERROR);
|
||||
|
||||
cx.render(rsx!{
|
||||
input {
|
||||
|
||||
@@ -6,7 +6,7 @@ Dioxus is a portable, performant, and ergonomic framework for building cross-pla
|
||||
|
||||
```rust
|
||||
fn app(cx: Scope) -> Element {
|
||||
let mut count = use_state(&cx, || 0);
|
||||
let mut count = use_state(cx, || 0);
|
||||
|
||||
cx.render(rsx!(
|
||||
h1 { "High-Five counter: {count}" }
|
||||
|
||||
@@ -10,7 +10,7 @@ A configuração básica para corrotinas é o _hook_ `use_coroutine`. A maioria
|
||||
|
||||
```rust
|
||||
fn app(cx: Scope) -> Element {
|
||||
let ws: &UseCoroutine<()> = use_coroutine(&cx, |rx| async move {
|
||||
let ws: &UseCoroutine<()> = use_coroutine(cx, |rx| async move {
|
||||
// Connect to some sort of service
|
||||
let mut conn = connect_to_ws_server().await;
|
||||
|
||||
@@ -27,7 +27,7 @@ Para muitos serviços, um _loop_ assíncrono simples lidará com a maioria dos c
|
||||
No entanto, se quisermos desabilitar temporariamente a corrotina, podemos "pausá-la" usando o método `pause` e "retomá-la" usando o método `resume`:
|
||||
|
||||
```rust
|
||||
let sync: &UseCoroutine<()> = use_coroutine(&cx, |rx| async move {
|
||||
let sync: &UseCoroutine<()> = use_coroutine(cx, |rx| async move {
|
||||
// code for syncing
|
||||
});
|
||||
|
||||
@@ -62,7 +62,7 @@ enum ProfileUpdate {
|
||||
SetAge(i32)
|
||||
}
|
||||
|
||||
let profile = use_coroutine(&cx, |mut rx: UnboundedReciver<ProfileUpdate>| async move {
|
||||
let profile = use_coroutine(cx, |mut rx: UnboundedReciver<ProfileUpdate>| async move {
|
||||
let mut server = connect_to_server().await;
|
||||
|
||||
while let Ok(msg) = rx.next().await {
|
||||
@@ -85,9 +85,9 @@ cx.render(rsx!{
|
||||
Para aplicativos suficientemente complexos, poderíamos criar vários "serviços" úteis diferentes que fazem um _loop_ nos canais para atualizar o aplicativo.
|
||||
|
||||
```rust
|
||||
let profile = use_coroutine(&cx, profile_service);
|
||||
let editor = use_coroutine(&cx, editor_service);
|
||||
let sync = use_coroutine(&cx, sync_service);
|
||||
let profile = use_coroutine(cx, profile_service);
|
||||
let editor = use_coroutine(cx, editor_service);
|
||||
let sync = use_coroutine(cx, sync_service);
|
||||
|
||||
async fn profile_service(rx: UnboundedReceiver<ProfileCommand>) {
|
||||
// do stuff
|
||||
@@ -108,9 +108,9 @@ Podemos combinar corrotinas com `Fermi` para emular o sistema `Thunk` do **Redux
|
||||
static USERNAME: Atom<String> = |_| "default".to_string();
|
||||
|
||||
fn app(cx: Scope) -> Element {
|
||||
let atoms = use_atom_root(&cx);
|
||||
let atoms = use_atom_root(cx);
|
||||
|
||||
use_coroutine(&cx, |rx| sync_service(rx, atoms.clone()));
|
||||
use_coroutine(cx, |rx| sync_service(rx, atoms.clone()));
|
||||
|
||||
cx.render(rsx!{
|
||||
Banner {}
|
||||
@@ -118,7 +118,7 @@ fn app(cx: Scope) -> Element {
|
||||
}
|
||||
|
||||
fn Banner(cx: Scope) -> Element {
|
||||
let username = use_read(&cx, USERNAME);
|
||||
let username = use_read(cx, USERNAME);
|
||||
|
||||
cx.render(rsx!{
|
||||
h1 { "Welcome back, {username}" }
|
||||
@@ -156,8 +156,8 @@ async fn sync_service(mut rx: UnboundedReceiver<SyncAction>, atoms: AtomRoot) {
|
||||
Para obter valores de uma corrotina, basta usar um identificador `UseState` e definir o valor sempre que sua corrotina concluir seu trabalho.
|
||||
|
||||
```rust
|
||||
let sync_status = use_state(&cx, || Status::Launching);
|
||||
let sync_task = use_coroutine(&cx, |rx: UnboundedReceiver<SyncAction>| {
|
||||
let sync_status = use_state(cx, || Status::Launching);
|
||||
let sync_task = use_coroutine(cx, |rx: UnboundedReceiver<SyncAction>| {
|
||||
to_owned![sync_status];
|
||||
async move {
|
||||
loop {
|
||||
@@ -174,7 +174,7 @@ Os identificadores de corrotina são injetados automaticamente por meio da API d
|
||||
|
||||
```rust
|
||||
fn Child(cx: Scope) -> Element {
|
||||
let sync_task = use_coroutine_handle::<SyncAction>(&cx);
|
||||
let sync_task = use_coroutine_handle::<SyncAction>(cx);
|
||||
|
||||
sync_task.send(SyncAction::SetUsername);
|
||||
}
|
||||
|
||||
@@ -53,14 +53,14 @@ A próxima "melhor" maneira de lidar com erros no Dioxus é combinar (`match`) o
|
||||
Para fazer isso, simplesmente temos um estado de erro embutido em nosso componente:
|
||||
|
||||
```rust
|
||||
let err = use_state(&cx, || None);
|
||||
let err = use_state(cx, || None);
|
||||
```
|
||||
|
||||
Sempre que realizarmos uma ação que gere um erro, definiremos esse estado de erro. Podemos então combinar o erro de várias maneiras (retorno antecipado, elemento de retorno etc.).
|
||||
|
||||
```rust
|
||||
fn Commandline(cx: Scope) -> Element {
|
||||
let error = use_state(&cx, || None);
|
||||
let error = use_state(cx, || None);
|
||||
|
||||
cx.render(match *error {
|
||||
Some(error) => rsx!(
|
||||
@@ -81,7 +81,7 @@ Se você estiver lidando com alguns componentes com um mínimo de aninhamento, b
|
||||
|
||||
```rust
|
||||
fn Commandline(cx: Scope) -> Element {
|
||||
let error = use_state(&cx, || None);
|
||||
let error = use_state(cx, || None);
|
||||
|
||||
if let Some(error) = **error {
|
||||
return cx.render(rsx!{ "An error occured" });
|
||||
@@ -120,7 +120,7 @@ Então, em nosso componente de nível superior, queremos tratar explicitamente o
|
||||
|
||||
```rust
|
||||
fn TopLevel(cx: Scope) -> Element {
|
||||
let error = use_read(&cx, INPUT_ERROR);
|
||||
let error = use_read(cx, INPUT_ERROR);
|
||||
|
||||
match error {
|
||||
TooLong => return cx.render(rsx!{ "FAILED: Too long!" }),
|
||||
@@ -134,7 +134,7 @@ Agora, sempre que um componente _downstream_ tiver um erro em suas ações, ele
|
||||
|
||||
```rust
|
||||
fn Commandline(cx: Scope) -> Element {
|
||||
let set_error = use_set(&cx, INPUT_ERROR);
|
||||
let set_error = use_set(cx, INPUT_ERROR);
|
||||
|
||||
cx.render(rsx!{
|
||||
input {
|
||||
|
||||
@@ -6,7 +6,7 @@ Dioxus é uma estrutura portátil, de alto desempenho e ergonômica para a const
|
||||
|
||||
```rust
|
||||
fn app(cx: Scope) -> Element {
|
||||
let mut count = use_state(&cx, || 0);
|
||||
let mut count = use_state(cx, || 0);
|
||||
|
||||
cx.render(rsx!(
|
||||
h1 { "High-Five counter: {count}" }
|
||||
|
||||
@@ -27,7 +27,7 @@ Dioxus is a recently-released library for building interactive user interfaces (
|
||||
|
||||
```rust
|
||||
fn app(cx: Scope) -> Element {
|
||||
let mut count = use_state(&cx, || 0);
|
||||
let mut count = use_state(cx, || 0);
|
||||
|
||||
cx.render(rsx! {
|
||||
h1 { "Count: {count}" }
|
||||
@@ -102,8 +102,8 @@ We're also using hooks to parse the URL parameters and segments so you can inter
|
||||
struct Query { name: String }
|
||||
|
||||
fn BlogPost(cx: Scope) -> Element {
|
||||
let post = use_route(&cx).segment("post")?;
|
||||
let query = use_route(&cx).query::<Query>()?;
|
||||
let post = use_route(cx).segment("post")?;
|
||||
let query = use_route(cx).query::<Query>()?;
|
||||
|
||||
cx.render(rsx!{
|
||||
"Viewing post {post}"
|
||||
@@ -128,7 +128,7 @@ static TITLE: Atom<&str> = |_| "Hello";
|
||||
|
||||
// Read the value from anywhere in the app, subscribing to any changes
|
||||
fn app(cx: Scope) -> Element {
|
||||
let title = use_read(&cx, TITLE);
|
||||
let title = use_read(cx, TITLE);
|
||||
cx.render(rsx!{
|
||||
h1 { "{title}" }
|
||||
Child {}
|
||||
@@ -137,7 +137,7 @@ fn app(cx: Scope) -> Element {
|
||||
|
||||
// Set the value from anywhere in the app
|
||||
fn Child(cx: Scope) -> Element {
|
||||
let set_title = use_set(&cx, TITLE);
|
||||
let set_title = use_set(cx, TITLE);
|
||||
cx.render(rsx!{
|
||||
button {
|
||||
onclick: move |_| set_title("goodbye"),
|
||||
@@ -245,7 +245,7 @@ First, we upgraded the `use_future` hook. It now supports dependencies, which le
|
||||
|
||||
```rust
|
||||
fn RenderDog(cx: Scope, breed: String) -> Element {
|
||||
let dog_request = use_future(&cx, (breed,), |(breed,)| async move {
|
||||
let dog_request = use_future(cx, (breed,), |(breed,)| async move {
|
||||
reqwest::get(format!("https://dog.ceo/api/breed/{}/images/random", breed))
|
||||
.await
|
||||
.unwrap()
|
||||
@@ -265,7 +265,7 @@ Additionally, we added better support for coroutines. You can now start, stop, r
|
||||
|
||||
```rust
|
||||
fn App(cx: Scope) -> Element {
|
||||
let sync_task = use_coroutine(&cx, |rx| async move {
|
||||
let sync_task = use_coroutine(cx, |rx| async move {
|
||||
connect_to_server().await;
|
||||
let state = MyState::new();
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ fn main() {
|
||||
}
|
||||
|
||||
fn app(cx: Scope) -> Element {
|
||||
let mut count = use_state(&cx, || 0);
|
||||
let mut count = use_state(cx, || 0);
|
||||
|
||||
cx.render(rsx! {
|
||||
h1 { "Count: {count}" }
|
||||
@@ -138,7 +138,7 @@ struct CardProps {
|
||||
}
|
||||
|
||||
static Card: Component<CardProps> = |cx| {
|
||||
let mut count = use_state(&cx, || 0);
|
||||
let mut count = use_state(cx, || 0);
|
||||
cx.render(rsx!(
|
||||
aside {
|
||||
h2 { "{cx.props.title}" }
|
||||
@@ -191,7 +191,7 @@ fn main() {
|
||||
}
|
||||
|
||||
fn app(cx: Scope) -> Element {
|
||||
let mut count = use_state(&cx, || 0);
|
||||
let mut count = use_state(cx, || 0);
|
||||
|
||||
cx.render(rsx! {
|
||||
h1 { "Count: {count}" }
|
||||
@@ -260,7 +260,7 @@ Dioxus understands the lifetimes of data borrowed from `Scope`, so you can safel
|
||||
|
||||
|
||||
```rust
|
||||
let name = use_state(&cx, || "asd");
|
||||
let name = use_state(cx, || "asd");
|
||||
rsx! {
|
||||
div {
|
||||
button { onclick: move |_| name.set("abc") }
|
||||
@@ -274,7 +274,7 @@ Because we know the lifetime of your handlers, we can also expose this to childr
|
||||
|
||||
```rust
|
||||
fn app(cx: Scope) -> Element {
|
||||
let name = use_state(&cx, || "asd");
|
||||
let name = use_state(cx, || "asd");
|
||||
cx.render(rsx!{
|
||||
Button { name: name }
|
||||
})
|
||||
|
||||
@@ -153,7 +153,7 @@ use dioxus::{
|
||||
...
|
||||
|
||||
fn blog_post(cx: Scope) -> Element {
|
||||
let route = use_route(&cx); // NEW
|
||||
let route = use_route(cx); // NEW
|
||||
let blog_text = "";
|
||||
|
||||
cx.render(rsx! {
|
||||
@@ -165,7 +165,7 @@ Dioxus Router provides built in methods to extract information from a route. We
|
||||
The ``segment`` method also parses the parameter into any type for us. We'll use a match expression that handles a parsing error and on success, uses our helper function to grab the blog post.
|
||||
```rs
|
||||
fn blog_post(cx: Scope) -> Element {
|
||||
let route = use_route(&cx);
|
||||
let route = use_route(cx);
|
||||
|
||||
// NEW
|
||||
let blog_text = match route.segment::<String>("post").unwrap() {
|
||||
|
||||
@@ -41,7 +41,7 @@ const RECT_STYLE: &str = r#"
|
||||
"#;
|
||||
|
||||
fn app(cx: Scope) -> Element {
|
||||
let events = use_ref(&cx, std::collections::VecDeque::new);
|
||||
let events = use_ref(cx, std::collections::VecDeque::new);
|
||||
|
||||
let log_event = move |event: Event| {
|
||||
let mut events = events.write();
|
||||
|
||||
@@ -19,7 +19,7 @@ fn main() {
|
||||
}
|
||||
|
||||
fn app(cx: Scope) -> Element {
|
||||
let val = use_state(&cx, || String::from("0"));
|
||||
let val = use_state(cx, || String::from("0"));
|
||||
|
||||
let input_digit = move |num: u8| {
|
||||
if val.get() == "0" {
|
||||
|
||||
+4
-4
@@ -16,10 +16,10 @@ pub struct Client {
|
||||
}
|
||||
|
||||
fn app(cx: Scope) -> Element {
|
||||
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 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);
|
||||
|
||||
cx.render(rsx!(
|
||||
body {
|
||||
|
||||
@@ -16,7 +16,7 @@ fn main() {
|
||||
}
|
||||
|
||||
fn app(cx: Scope) -> Element {
|
||||
// let nf = NodeFactory::new(&cx);
|
||||
// let nf = NodeFactory::new(cx);
|
||||
|
||||
// let mut attrs = dioxus::core::exports::bumpalo::collections::Vec::new_in(nf.bump());
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ fn main() {
|
||||
}
|
||||
|
||||
fn app(cx: Scope) -> Element {
|
||||
let disabled = use_state(&cx, || false);
|
||||
let disabled = use_state(cx, || false);
|
||||
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
|
||||
@@ -5,7 +5,7 @@ fn main() {
|
||||
}
|
||||
|
||||
fn app(cx: Scope) -> Element {
|
||||
let val = use_state(&cx, || "0.0001");
|
||||
let val = use_state(cx, || "0.0001");
|
||||
|
||||
let num = match val.parse::<f32>() {
|
||||
Err(_) => return cx.render(rsx!("Parsing failed")),
|
||||
|
||||
+2
-2
@@ -5,8 +5,8 @@ fn main() {
|
||||
}
|
||||
|
||||
fn app(cx: Scope) -> Element {
|
||||
let script = use_state(&cx, String::new);
|
||||
let eval = dioxus_desktop::use_eval(&cx);
|
||||
let script = use_state(cx, String::new);
|
||||
let eval = dioxus_desktop::use_eval(cx);
|
||||
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
|
||||
+3
-3
@@ -10,7 +10,7 @@ fn main() {
|
||||
static NAME: Atom<String> = |_| "world".to_string();
|
||||
|
||||
fn app(cx: Scope) -> Element {
|
||||
let name = use_read(&cx, NAME);
|
||||
let name = use_read(cx, NAME);
|
||||
|
||||
cx.render(rsx! {
|
||||
div { "hello {name}!" }
|
||||
@@ -20,7 +20,7 @@ fn app(cx: Scope) -> Element {
|
||||
}
|
||||
|
||||
fn Child(cx: Scope) -> Element {
|
||||
let set_name = use_set(&cx, NAME);
|
||||
let set_name = use_set(cx, NAME);
|
||||
|
||||
cx.render(rsx! {
|
||||
button {
|
||||
@@ -33,7 +33,7 @@ fn Child(cx: Scope) -> Element {
|
||||
static NAMES: AtomRef<Vec<String>> = |_| vec!["world".to_string()];
|
||||
|
||||
fn ChildWithRef(cx: Scope) -> Element {
|
||||
let names = use_atom_ref(&cx, NAMES);
|
||||
let names = use_atom_ref(cx, NAMES);
|
||||
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
|
||||
@@ -19,7 +19,7 @@ fn main() {
|
||||
}
|
||||
|
||||
fn app(cx: Scope) -> Element {
|
||||
let files = use_ref(&cx, Files::new);
|
||||
let files = use_ref(cx, Files::new);
|
||||
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
|
||||
@@ -32,8 +32,8 @@ impl Label {
|
||||
}
|
||||
|
||||
fn app(cx: Scope) -> Element {
|
||||
let items = use_ref(&cx, Vec::new);
|
||||
let selected = use_state(&cx, || None);
|
||||
let items = use_ref(cx, Vec::new);
|
||||
let selected = use_state(cx, || None);
|
||||
|
||||
cx.render(rsx! {
|
||||
div { class: "container",
|
||||
|
||||
@@ -20,7 +20,7 @@ fn main() {
|
||||
}
|
||||
|
||||
fn app(cx: Scope) -> Element {
|
||||
let val = use_state(&cx, || 0);
|
||||
let val = use_state(cx, || 0);
|
||||
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
|
||||
@@ -28,7 +28,7 @@ fn main() {
|
||||
}
|
||||
|
||||
fn app(cx: Scope) -> Element {
|
||||
let state = use_state(&cx, || 1);
|
||||
let state = use_state(cx, || 1);
|
||||
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
|
||||
@@ -36,7 +36,7 @@ fn main() {
|
||||
}
|
||||
|
||||
fn app(cx: Scope) -> Element {
|
||||
let state = use_ref(&cx, Calculator::new);
|
||||
let state = use_ref(cx, Calculator::new);
|
||||
|
||||
cx.render(rsx! {
|
||||
style { include_str!("./assets/calculator.css") }
|
||||
|
||||
@@ -15,7 +15,7 @@ fn main() {
|
||||
}
|
||||
|
||||
fn app(cx: Scope) -> Element {
|
||||
let state = use_state(&cx, PlayerState::new);
|
||||
let state = use_state(cx, PlayerState::new);
|
||||
|
||||
cx.render(rsx!(
|
||||
div {
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@ fn main() {
|
||||
}
|
||||
|
||||
fn app(cx: Scope) -> Element {
|
||||
let mut count = use_state(&cx, || 0);
|
||||
let mut count = use_state(cx, || 0);
|
||||
|
||||
cx.render(rsx! {
|
||||
h1 { "High-Five counter: {count}" }
|
||||
|
||||
+3
-3
@@ -30,7 +30,7 @@ fn app(cx: Scope) -> Element {
|
||||
}
|
||||
|
||||
fn BlogPost(cx: Scope) -> Element {
|
||||
let post = dioxus_router::use_route(&cx).last_segment().unwrap();
|
||||
let post = dioxus_router::use_route(cx).last_segment().unwrap();
|
||||
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
@@ -46,9 +46,9 @@ struct Query {
|
||||
}
|
||||
|
||||
fn User(cx: Scope) -> Element {
|
||||
let post = dioxus_router::use_route(&cx).last_segment().unwrap();
|
||||
let post = dioxus_router::use_route(cx).last_segment().unwrap();
|
||||
|
||||
let query = dioxus_router::use_route(&cx)
|
||||
let query = dioxus_router::use_route(cx)
|
||||
.query::<Query>()
|
||||
.unwrap_or(Query { bold: false });
|
||||
|
||||
|
||||
@@ -13,14 +13,14 @@ fn main() {
|
||||
}
|
||||
|
||||
fn example(cx: Scope) -> Element {
|
||||
let items = use_state(&cx, || {
|
||||
let items = use_state(cx, || {
|
||||
vec![Thing {
|
||||
a: "asd".to_string(),
|
||||
b: 10,
|
||||
}]
|
||||
});
|
||||
|
||||
let things = use_ref(&cx, || {
|
||||
let things = use_ref(cx, || {
|
||||
vec![Thing {
|
||||
a: "asd".to_string(),
|
||||
b: 10,
|
||||
@@ -28,7 +28,7 @@ fn example(cx: Scope) -> Element {
|
||||
});
|
||||
let things_list = things.read();
|
||||
|
||||
let mything = use_ref(&cx, || Some(String::from("asd")));
|
||||
let mything = use_ref(cx, || Some(String::from("asd")));
|
||||
let mything_read = mything.read();
|
||||
|
||||
cx.render(rsx!(
|
||||
|
||||
@@ -200,7 +200,7 @@ fn app(cx: Scope) -> Element {
|
||||
|
||||
// helper functions
|
||||
// Anything that implements IntoVnode can be dropped directly into Rsx
|
||||
helper(&cx, "hello world!")
|
||||
helper(cx, "hello world!")
|
||||
|
||||
// Strings can be supplied directly
|
||||
String::from("Hello world!")
|
||||
|
||||
+5
-13
@@ -2,16 +2,13 @@
|
||||
//!
|
||||
//! This example shows how we can render the Dioxus Virtualdom using SSR.
|
||||
|
||||
use std::fmt::Write;
|
||||
|
||||
use dioxus::prelude::*;
|
||||
use dioxus_ssr::config::Config;
|
||||
|
||||
fn main() {
|
||||
// We can render VirtualDoms
|
||||
let mut vdom = VirtualDom::new(app);
|
||||
let _ = vdom.rebuild();
|
||||
println!("{}", dioxus_ssr::render_vdom(&vdom));
|
||||
println!("{}", dioxus_ssr::render(&vdom));
|
||||
|
||||
// Or we can render rsx! calls themselves
|
||||
println!(
|
||||
@@ -24,17 +21,12 @@ fn main() {
|
||||
);
|
||||
|
||||
// We can configure the SSR rendering to add ids for rehydration
|
||||
println!(
|
||||
"{}",
|
||||
dioxus_ssr::render_vdom_cfg(&vdom, Config::default().pre_render(true))
|
||||
);
|
||||
println!("{}", dioxus_ssr::pre_render(&vdom));
|
||||
|
||||
// We can even render as a writer
|
||||
// We can render to a buf directly too
|
||||
let mut file = String::new();
|
||||
let _ = file.write_fmt(format_args!(
|
||||
"{}",
|
||||
dioxus_ssr::SsrRender::default().render_vdom(&vdom)
|
||||
));
|
||||
let mut renderer = dioxus_ssr::Renderer::default();
|
||||
renderer.render_to(&mut file, &vdom).unwrap();
|
||||
println!("{}", file);
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ fn app(cx: Scope) -> Element {
|
||||
/// Suspense is achieved my moving the future into only the component that
|
||||
/// actually renders the data.
|
||||
fn Doggo(cx: Scope) -> Element {
|
||||
let fut = use_future(&cx, (), |_| async move {
|
||||
let fut = use_future(cx, (), |_| async move {
|
||||
reqwest::get("https://dog.ceo/api/breeds/image/random/")
|
||||
.await
|
||||
.unwrap()
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ fn main() {
|
||||
}
|
||||
|
||||
fn app(cx: Scope) -> Element {
|
||||
let val = use_state(&cx, || 5);
|
||||
let val = use_state(cx, || 5);
|
||||
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
|
||||
+2
-2
@@ -10,9 +10,9 @@ fn main() {
|
||||
}
|
||||
|
||||
fn app(cx: Scope) -> Element {
|
||||
let count = use_state(&cx, || 0);
|
||||
let count = use_state(cx, || 0);
|
||||
|
||||
use_future(&cx, (), move |_| {
|
||||
use_future(cx, (), move |_| {
|
||||
let mut count = count.clone();
|
||||
async move {
|
||||
loop {
|
||||
|
||||
@@ -7,7 +7,7 @@ fn main() {
|
||||
}
|
||||
|
||||
fn app(cx: Scope) -> Element {
|
||||
let model = use_state(&cx, || String::from("asd"));
|
||||
let model = use_state(cx, || String::from("asd"));
|
||||
|
||||
println!("{}", model);
|
||||
|
||||
|
||||
@@ -12,15 +12,15 @@ fn main() {
|
||||
}
|
||||
|
||||
fn app(cx: Scope) -> Element {
|
||||
let window = dioxus_desktop::use_window(&cx);
|
||||
let window = dioxus_desktop::use_window(cx);
|
||||
|
||||
// if you want to make window fullscreen, you need close the resizable.
|
||||
// window.set_fullscreen(true);
|
||||
// window.set_resizable(false);
|
||||
|
||||
let fullscreen = use_state(&cx, || false);
|
||||
let always_on_top = use_state(&cx, || false);
|
||||
let decorations = use_state(&cx, || false);
|
||||
let fullscreen = use_state(cx, || false);
|
||||
let always_on_top = use_state(cx, || false);
|
||||
let decorations = use_state(cx, || false);
|
||||
|
||||
cx.render(rsx!(
|
||||
link { href:"https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css", rel:"stylesheet" }
|
||||
|
||||
@@ -6,9 +6,9 @@ fn main() {
|
||||
}
|
||||
|
||||
fn app(cx: Scope) -> Element {
|
||||
let window = use_window(&cx);
|
||||
let window = use_window(cx);
|
||||
|
||||
let level = use_state(&cx, || 1.0);
|
||||
let level = use_state(cx, || 1.0);
|
||||
cx.render(rsx! {
|
||||
input {
|
||||
r#type: "number",
|
||||
|
||||
@@ -9,7 +9,7 @@ fn main() {
|
||||
}
|
||||
|
||||
fn app(cx: Scope) -> Element {
|
||||
let contents = use_state(&cx, || {
|
||||
let contents = use_state(cx, || {
|
||||
String::from("<script>alert(\"hello world\")</script>")
|
||||
});
|
||||
|
||||
|
||||
+2
-2
@@ -233,7 +233,7 @@ use hooks to define state and modify it from within listeners.
|
||||
|
||||
```rust, ignore
|
||||
fn app(cx: Scope) -> Element {
|
||||
let name = use_state(&cx, || "world");
|
||||
let name = use_state(cx, || "world");
|
||||
|
||||
render!("hello {name}!")
|
||||
}
|
||||
@@ -280,7 +280,7 @@ fn main() {
|
||||
}
|
||||
|
||||
fn App(cx: Scope) -> Element {
|
||||
let count = use_state(&cx, || 0);
|
||||
let count = use_state(cx, || 0);
|
||||
|
||||
cx.render(rsx!(
|
||||
div { "Count: {count}" }
|
||||
|
||||
@@ -54,7 +54,7 @@ Dioxus 是一个可移植的、高性能的、符合人体工程学的框架,
|
||||
|
||||
```rust
|
||||
fn app(cx: Scope) -> Element {
|
||||
let mut count = use_state(&cx, || 0);
|
||||
let mut count = use_state(cx, || 0);
|
||||
|
||||
cx.render(rsx! {
|
||||
h1 { "High-Five counter: {count}" }
|
||||
|
||||
@@ -406,8 +406,8 @@ enum Patch {
|
||||
```
|
||||
|
||||
```rust
|
||||
let node_ref = use_node_ref(&cx);
|
||||
use_effect(&cx, || {
|
||||
let node_ref = use_node_ref(cx);
|
||||
use_effect(cx, || {
|
||||
|
||||
}, []);
|
||||
div { ref: node_ref,
|
||||
|
||||
@@ -21,7 +21,8 @@ use std::{
|
||||
/// }
|
||||
/// ```
|
||||
pub struct Event<T: 'static + ?Sized> {
|
||||
pub(crate) data: Rc<T>,
|
||||
/// The data associated with this event
|
||||
pub data: Rc<T>,
|
||||
pub(crate) propogates: Rc<Cell<bool>>,
|
||||
}
|
||||
|
||||
|
||||
@@ -514,6 +514,14 @@ impl<'a> IntoTemplate<'a> for VNode<'a> {
|
||||
self
|
||||
}
|
||||
}
|
||||
impl<'a> IntoTemplate<'a> for Element<'a> {
|
||||
fn into_template(self, _cx: &'a ScopeState) -> VNode<'a> {
|
||||
match self {
|
||||
Ok(val) => val.into_template(_cx),
|
||||
_ => VNode::empty().unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<'a, 'b> IntoTemplate<'a> for LazyNodes<'a, 'b> {
|
||||
fn into_template(self, cx: &'a ScopeState) -> VNode<'a> {
|
||||
self.call(cx)
|
||||
|
||||
@@ -21,9 +21,12 @@ pub fn use_window(cx: &ScopeState) -> &DesktopContext {
|
||||
|
||||
/// Get a closure that executes any JavaScript in the WebView context.
|
||||
pub fn use_eval(cx: &ScopeState) -> &Rc<dyn Fn(String)> {
|
||||
let desktop = use_window(cx).clone();
|
||||
let desktop = use_window(cx);
|
||||
|
||||
&*cx.use_hook(|| Rc::new(move |script| desktop.eval(script)) as Rc<dyn Fn(String)>)
|
||||
&*cx.use_hook(|| {
|
||||
let desktop = desktop.clone();
|
||||
Rc::new(move |script| desktop.eval(script))
|
||||
} as Rc<dyn Fn(String)>)
|
||||
}
|
||||
|
||||
/// An imperative interface to the current window.
|
||||
|
||||
@@ -4,26 +4,26 @@ use rand::prelude::*;
|
||||
fn main() {
|
||||
let mut dom = VirtualDom::new(app);
|
||||
|
||||
dom.rebuild();
|
||||
_ = dom.rebuild();
|
||||
|
||||
for _ in 0..1000 {
|
||||
dom.rebuild();
|
||||
_ = dom.rebuild();
|
||||
}
|
||||
}
|
||||
|
||||
fn app(cx: Scope) -> Element {
|
||||
let mut rng = SmallRng::from_entropy();
|
||||
|
||||
render! (
|
||||
cx.render(rsx! (
|
||||
table {
|
||||
tbody {
|
||||
(0..10_000_usize).map(|f| {
|
||||
let label = Label::new(&mut rng);
|
||||
rsx!( Row { row_id: f, label: label } )
|
||||
rsx!( table_row { row_id: f, label: label } )
|
||||
})
|
||||
}
|
||||
}
|
||||
)
|
||||
))
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Props)]
|
||||
@@ -31,9 +31,9 @@ struct RowProps {
|
||||
row_id: usize,
|
||||
label: Label,
|
||||
}
|
||||
fn Row(cx: Scope<RowProps>) -> Element {
|
||||
fn table_row(cx: Scope<RowProps>) -> Element {
|
||||
let [adj, col, noun] = cx.props.label.0;
|
||||
render! {
|
||||
cx.render(rsx! {
|
||||
tr {
|
||||
td { class:"col-md-1", "{cx.props.row_id}" }
|
||||
td { class:"col-md-1", onclick: move |_| { /* run onselect */ },
|
||||
@@ -46,7 +46,7 @@ fn Row(cx: Scope<RowProps>) -> Element {
|
||||
}
|
||||
td { class: "col-md-6" }
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
|
||||
@@ -44,7 +44,7 @@ From anywhere in our app, we can read our the value of our atom:
|
||||
|
||||
```rust, ignore
|
||||
fn NameCard(cx: Scope) -> Element {
|
||||
let name = use_read(&cx, NAME);
|
||||
let name = use_read(cx, NAME);
|
||||
cx.render(rsx!{ h1 { "Hello, {name}"} })
|
||||
}
|
||||
```
|
||||
@@ -53,7 +53,7 @@ We can also set the value of our atom, also from anywhere in our app:
|
||||
|
||||
```rust, ignore
|
||||
fn NameCard(cx: Scope) -> Element {
|
||||
let set_name = use_set(&cx, NAME);
|
||||
let set_name = use_set(cx, NAME);
|
||||
cx.render(rsx!{
|
||||
button {
|
||||
onclick: move |_| set_name("Fermi"),
|
||||
|
||||
@@ -19,7 +19,7 @@ use std::{
|
||||
/// static COUNT: Atom<u32> = |_| 0;
|
||||
///
|
||||
/// fn Example(cx: Scope) -> Element {
|
||||
/// let mut count = use_atom_state(&cx, COUNT);
|
||||
/// let mut count = use_atom_state(cx, COUNT);
|
||||
///
|
||||
/// cx.render(rsx! {
|
||||
/// div {
|
||||
@@ -74,7 +74,7 @@ impl<T: 'static> AtomState<T> {
|
||||
///
|
||||
/// ```rust, ignore
|
||||
/// fn component(cx: Scope) -> Element {
|
||||
/// let count = use_state(&cx, || 0);
|
||||
/// let count = use_state(cx, || 0);
|
||||
/// cx.spawn({
|
||||
/// let set_count = count.to_owned();
|
||||
/// async move {
|
||||
@@ -101,7 +101,7 @@ impl<T: 'static> AtomState<T> {
|
||||
///
|
||||
/// ```rust, ignore
|
||||
/// fn component(cx: Scope) -> Element {
|
||||
/// let value = use_state(&cx, || 0);
|
||||
/// let value = use_state(cx, || 0);
|
||||
///
|
||||
/// rsx!{
|
||||
/// Component {
|
||||
@@ -128,7 +128,7 @@ impl<T: 'static> AtomState<T> {
|
||||
/// # use dioxus_core::prelude::*;
|
||||
/// # use dioxus_hooks::*;
|
||||
/// fn component(cx: Scope) -> Element {
|
||||
/// let value = use_state(&cx, || 0);
|
||||
/// let value = use_state(cx, || 0);
|
||||
///
|
||||
/// // to increment the value
|
||||
/// value.modify(|v| v + 1);
|
||||
@@ -168,7 +168,7 @@ impl<T: 'static> AtomState<T> {
|
||||
/// # use dioxus_core::prelude::*;
|
||||
/// # use dioxus_hooks::*;
|
||||
/// fn component(cx: Scope) -> Element {
|
||||
/// let value = use_state(&cx, || 0);
|
||||
/// let value = use_state(cx, || 0);
|
||||
///
|
||||
/// let as_rc = value.get();
|
||||
/// assert_eq!(as_rc.as_ref(), &0);
|
||||
@@ -190,7 +190,7 @@ impl<T: 'static> AtomState<T> {
|
||||
///
|
||||
/// ```rust, ignore
|
||||
/// fn component(cx: Scope) -> Element {
|
||||
/// let count = use_state(&cx, || 0);
|
||||
/// let count = use_state(cx, || 0);
|
||||
/// cx.spawn({
|
||||
/// let count = count.to_owned();
|
||||
/// async move {
|
||||
@@ -220,7 +220,7 @@ impl<T: Clone> AtomState<T> {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// let val = use_state(&cx, || 0);
|
||||
/// let val = use_state(cx, || 0);
|
||||
///
|
||||
/// val.with_mut(|v| *v = 1);
|
||||
/// ```
|
||||
@@ -243,7 +243,7 @@ impl<T: Clone> AtomState<T> {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```ignore
|
||||
/// let val = use_state(&cx, || 0);
|
||||
/// let val = use_state(cx, || 0);
|
||||
///
|
||||
/// *val.make_mut() += 1;
|
||||
/// ```
|
||||
|
||||
@@ -15,8 +15,8 @@ You can always use it "normally" with the `split` method:
|
||||
|
||||
```rust
|
||||
// Rusty-smart-pointer 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();
|
||||
```
|
||||
@@ -5,7 +5,7 @@
|
||||
///
|
||||
///
|
||||
/// ```ignore
|
||||
/// let (data) = use_ref(&cx, || {});
|
||||
/// let (data) = use_ref(cx, || {});
|
||||
///
|
||||
/// let handle_thing = move |_| {
|
||||
/// to_owned![data]
|
||||
@@ -30,8 +30,8 @@ pub use usestate::{use_state, UseState};
|
||||
mod useref;
|
||||
pub use useref::*;
|
||||
|
||||
// mod use_shared_state;
|
||||
// pub use use_shared_state::*;
|
||||
mod use_shared_state;
|
||||
pub use use_shared_state::*;
|
||||
|
||||
mod usecoroutine;
|
||||
pub use usecoroutine::*;
|
||||
|
||||
@@ -60,10 +60,10 @@ impl<T> ProvidedStateInner<T> {
|
||||
///
|
||||
///
|
||||
///
|
||||
pub fn use_context<T: 'static>(cx: &ScopeState) -> Option<UseSharedState<T>> {
|
||||
pub fn use_shared_state<T: 'static>(cx: &ScopeState) -> Option<UseSharedState<T>> {
|
||||
let state = cx.use_hook(|| {
|
||||
let scope_id = cx.scope_id();
|
||||
let root = cx.consume_context::<ProvidedState<T>>().cloned();
|
||||
let root = cx.consume_context::<ProvidedState<T>>();
|
||||
|
||||
if let Some(root) = root.as_ref() {
|
||||
root.borrow_mut().consumers.insert(scope_id);
|
||||
@@ -165,14 +165,7 @@ where
|
||||
}
|
||||
|
||||
/// Provide some state for components down the hierarchy to consume without having to drill props.
|
||||
///
|
||||
///
|
||||
///
|
||||
///
|
||||
///
|
||||
///
|
||||
///
|
||||
pub fn use_context_provider<T: 'static>(cx: &ScopeState, f: impl FnOnce() -> T) {
|
||||
pub fn use_shared_state_provider<T: 'static>(cx: &ScopeState, f: impl FnOnce() -> T) {
|
||||
cx.use_hook(|| {
|
||||
let state: ProvidedState<T> = Rc::new(RefCell::new(ProvidedStateInner {
|
||||
value: Rc::new(RefCell::new(f())),
|
||||
|
||||
@@ -16,7 +16,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(&cx, || HashMap::new());
|
||||
let (map, set_map) = use_state(cx, || HashMap::new());
|
||||
set_map({
|
||||
let mut newmap = map.clone();
|
||||
newmap.set(key, value);
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
use dioxus_core::ScopeState;
|
||||
|
||||
/// Consume some context in the tree, providing a sharable handle to the value
|
||||
///
|
||||
/// Does not regenerate the value if the value is changed at the parent.
|
||||
pub fn use_context<T: 'static + Clone>(cx: &ScopeState) -> Option<&T> {
|
||||
cx.use_hook(|| cx.consume_context::<T>()).as_ref()
|
||||
}
|
||||
|
||||
@@ -2,8 +2,6 @@ use dioxus_core::{ScopeState, TaskId};
|
||||
pub use futures_channel::mpsc::{UnboundedReceiver, UnboundedSender};
|
||||
use std::future::Future;
|
||||
|
||||
use crate::{use_context, use_context_provider};
|
||||
|
||||
/// Maintain a handle over a future that can be paused, resumed, and canceled.
|
||||
///
|
||||
/// This is an upgraded form of [`use_future`] with an integrated channel system.
|
||||
@@ -44,7 +42,7 @@ use crate::{use_context, use_context_provider};
|
||||
/// Stop,
|
||||
/// }
|
||||
///
|
||||
/// let chat_client = use_coroutine(&cx, |rx: UnboundedReceiver<Action>| async move {
|
||||
/// let chat_client = use_coroutine(cx, |rx: UnboundedReceiver<Action>| async move {
|
||||
/// while let Some(action) = rx.next().await {
|
||||
/// match action {
|
||||
/// Action::Start => {}
|
||||
@@ -67,10 +65,10 @@ where
|
||||
G: FnOnce(UnboundedReceiver<M>) -> F,
|
||||
F: Future<Output = ()> + 'static,
|
||||
{
|
||||
use_context_provider(cx, || {
|
||||
cx.use_hook(|| {
|
||||
let (tx, rx) = futures_channel::mpsc::unbounded();
|
||||
let task = cx.push_future(init(rx));
|
||||
Coroutine { tx, task }
|
||||
cx.provide_context(Coroutine { tx, task })
|
||||
})
|
||||
}
|
||||
|
||||
@@ -78,7 +76,8 @@ where
|
||||
///
|
||||
/// See the docs for [`use_coroutine`] for more details.
|
||||
pub fn use_coroutine_handle<M: 'static>(cx: &ScopeState) -> Option<&Coroutine<M>> {
|
||||
use_context::<Coroutine<M>>(cx)
|
||||
cx.use_hook(|| cx.consume_context::<Coroutine<M>>())
|
||||
.as_ref()
|
||||
}
|
||||
|
||||
pub struct Coroutine<T> {
|
||||
@@ -119,15 +118,15 @@ mod tests {
|
||||
use futures_util::StreamExt;
|
||||
|
||||
fn app(cx: Scope, name: String) -> Element {
|
||||
let task = use_coroutine(&cx, |mut rx: UnboundedReceiver<i32>| async move {
|
||||
let task = use_coroutine(cx, |mut rx: UnboundedReceiver<i32>| async move {
|
||||
while let Some(msg) = rx.next().await {
|
||||
println!("got message: {}", msg);
|
||||
}
|
||||
});
|
||||
|
||||
let task2 = use_coroutine(&cx, view_task);
|
||||
let task2 = use_coroutine(cx, view_task);
|
||||
|
||||
let task3 = use_coroutine(&cx, |rx| complex_task(rx, 10));
|
||||
let task3 = use_coroutine(cx, |rx| complex_task(rx, 10));
|
||||
|
||||
todo!()
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ use crate::UseFutureDep;
|
||||
///
|
||||
/// #[inline_props]
|
||||
/// fn app(cx: Scope, name: &str) -> Element {
|
||||
/// use_effect(&cx, (name,), |(name,)| async move {
|
||||
/// use_effect(cx, (name,), |(name,)| async move {
|
||||
/// set_title(name);
|
||||
/// }))
|
||||
/// }
|
||||
@@ -72,17 +72,17 @@ mod tests {
|
||||
|
||||
fn app(cx: Scope<MyProps>) -> Element {
|
||||
// should only ever run once
|
||||
use_effect(&cx, (), |_| async move {
|
||||
use_effect(cx, (), |_| async move {
|
||||
//
|
||||
});
|
||||
|
||||
// runs when a is changed
|
||||
use_effect(&cx, (&cx.props.a,), |(a,)| async move {
|
||||
use_effect(cx, (&cx.props.a,), |(a,)| async move {
|
||||
//
|
||||
});
|
||||
|
||||
// runs when a or b is changed
|
||||
use_effect(&cx, (&cx.props.a, &cx.props.b), |(a, b)| async move {
|
||||
use_effect(cx, (&cx.props.a, &cx.props.b), |(a, b)| async move {
|
||||
//
|
||||
});
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ use std::{
|
||||
///
|
||||
/// ```ignore
|
||||
/// const Example: Component = |cx| {
|
||||
/// let count = use_state(&cx, || 0);
|
||||
/// let count = use_state(cx, || 0);
|
||||
///
|
||||
/// cx.render(rsx! {
|
||||
/// div {
|
||||
@@ -92,7 +92,7 @@ impl<T: 'static> UseState<T> {
|
||||
///
|
||||
/// ```rust, ignore
|
||||
/// fn component(cx: Scope) -> Element {
|
||||
/// let count = use_state(&cx, || 0);
|
||||
/// let count = use_state(cx, || 0);
|
||||
/// cx.spawn({
|
||||
/// let set_count = count.to_owned();
|
||||
/// async move {
|
||||
@@ -119,7 +119,7 @@ impl<T: 'static> UseState<T> {
|
||||
///
|
||||
/// ```rust, ignore
|
||||
/// fn component(cx: Scope) -> Element {
|
||||
/// let value = use_state(&cx, || 0);
|
||||
/// let value = use_state(cx, || 0);
|
||||
///
|
||||
/// rsx!{
|
||||
/// Component {
|
||||
@@ -144,7 +144,7 @@ impl<T: 'static> UseState<T> {
|
||||
/// # use dioxus_core::prelude::*;
|
||||
/// # use dioxus_hooks::*;
|
||||
/// fn component(cx: Scope) -> Element {
|
||||
/// let value = use_state(&cx, || 0);
|
||||
/// let value = use_state(cx, || 0);
|
||||
///
|
||||
/// // to increment the value
|
||||
/// value.modify(|v| v + 1);
|
||||
@@ -185,7 +185,7 @@ impl<T: 'static> UseState<T> {
|
||||
/// # use dioxus_core::prelude::*;
|
||||
/// # use dioxus_hooks::*;
|
||||
/// fn component(cx: Scope) -> Element {
|
||||
/// let value = use_state(&cx, || 0);
|
||||
/// let value = use_state(cx, || 0);
|
||||
///
|
||||
/// let as_rc = value.get();
|
||||
/// assert_eq!(as_rc.as_ref(), &0);
|
||||
@@ -207,7 +207,7 @@ impl<T: 'static> UseState<T> {
|
||||
///
|
||||
/// ```rust, ignore
|
||||
/// fn component(cx: Scope) -> Element {
|
||||
/// let count = use_state(&cx, || 0);
|
||||
/// let count = use_state(cx, || 0);
|
||||
/// cx.spawn({
|
||||
/// let count = count.to_owned();
|
||||
/// async move {
|
||||
@@ -237,7 +237,7 @@ impl<T: Clone> UseState<T> {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust, ignore
|
||||
/// let val = use_state(&cx, || 0);
|
||||
/// let val = use_state(cx, || 0);
|
||||
///
|
||||
/// val.with_mut(|v| *v = 1);
|
||||
/// ```
|
||||
@@ -269,7 +269,7 @@ impl<T: Clone> UseState<T> {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust, ignore
|
||||
/// let val = use_state(&cx, || 0);
|
||||
/// let val = use_state(cx, || 0);
|
||||
///
|
||||
/// *val.make_mut() += 1;
|
||||
/// ```
|
||||
@@ -448,7 +448,7 @@ impl<T: Div<Output = T> + Copy> std::ops::DivAssign<T> for UseState<T> {
|
||||
fn api_makes_sense() {
|
||||
#[allow(unused)]
|
||||
fn app(cx: Scope) -> Element {
|
||||
let val = use_state(&cx, || 0);
|
||||
let val = use_state(cx, || 0);
|
||||
|
||||
val.set(0);
|
||||
val.modify(|v| v + 1);
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
mod keys;
|
||||
pub use keys::*;
|
||||
|
||||
macro_rules! impl_event {
|
||||
(
|
||||
$data:ty;
|
||||
|
||||
@@ -1,370 +0,0 @@
|
||||
#[cfg_attr(
|
||||
feature = "serialize",
|
||||
derive(serde_repr::Serialize_repr, serde_repr::Deserialize_repr)
|
||||
)]
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
#[repr(u8)]
|
||||
pub enum KeyCode {
|
||||
// That key has no keycode, = 0
|
||||
// break, = 3
|
||||
// backspace / delete, = 8
|
||||
// tab, = 9
|
||||
// clear, = 12
|
||||
// enter, = 13
|
||||
// shift, = 16
|
||||
// ctrl, = 17
|
||||
// alt, = 18
|
||||
// pause/break, = 19
|
||||
// caps lock, = 20
|
||||
// hangul, = 21
|
||||
// hanja, = 25
|
||||
// escape, = 27
|
||||
// conversion, = 28
|
||||
// non-conversion, = 29
|
||||
// spacebar, = 32
|
||||
// page up, = 33
|
||||
// page down, = 34
|
||||
// end, = 35
|
||||
// home, = 36
|
||||
// left arrow, = 37
|
||||
// up arrow, = 38
|
||||
// right arrow, = 39
|
||||
// down arrow, = 40
|
||||
// select, = 41
|
||||
// print, = 42
|
||||
// execute, = 43
|
||||
// Print Screen, = 44
|
||||
// insert, = 45
|
||||
// delete, = 46
|
||||
// help, = 47
|
||||
// 0, = 48
|
||||
// 1, = 49
|
||||
// 2, = 50
|
||||
// 3, = 51
|
||||
// 4, = 52
|
||||
// 5, = 53
|
||||
// 6, = 54
|
||||
// 7, = 55
|
||||
// 8, = 56
|
||||
// 9, = 57
|
||||
// :, = 58
|
||||
// semicolon (firefox), equals, = 59
|
||||
// <, = 60
|
||||
// equals (firefox), = 61
|
||||
// ß, = 63
|
||||
// @ (firefox), = 64
|
||||
// a, = 65
|
||||
// b, = 66
|
||||
// c, = 67
|
||||
// d, = 68
|
||||
// e, = 69
|
||||
// f, = 70
|
||||
// g, = 71
|
||||
// h, = 72
|
||||
// i, = 73
|
||||
// j, = 74
|
||||
// k, = 75
|
||||
// l, = 76
|
||||
// m, = 77
|
||||
// n, = 78
|
||||
// o, = 79
|
||||
// p, = 80
|
||||
// q, = 81
|
||||
// r, = 82
|
||||
// s, = 83
|
||||
// t, = 84
|
||||
// u, = 85
|
||||
// v, = 86
|
||||
// w, = 87
|
||||
// x, = 88
|
||||
// y, = 89
|
||||
// z, = 90
|
||||
// Windows Key / Left ⌘ / Chromebook Search key, = 91
|
||||
// right window key, = 92
|
||||
// Windows Menu / Right ⌘, = 93
|
||||
// sleep, = 95
|
||||
// numpad 0, = 96
|
||||
// numpad 1, = 97
|
||||
// numpad 2, = 98
|
||||
// numpad 3, = 99
|
||||
// numpad 4, = 100
|
||||
// numpad 5, = 101
|
||||
// numpad 6, = 102
|
||||
// numpad 7, = 103
|
||||
// numpad 8, = 104
|
||||
// numpad 9, = 105
|
||||
// multiply, = 106
|
||||
// add, = 107
|
||||
// numpad period (firefox), = 108
|
||||
// subtract, = 109
|
||||
// decimal point, = 110
|
||||
// divide, = 111
|
||||
// f1, = 112
|
||||
// f2, = 113
|
||||
// f3, = 114
|
||||
// f4, = 115
|
||||
// f5, = 116
|
||||
// f6, = 117
|
||||
// f7, = 118
|
||||
// f8, = 119
|
||||
// f9, = 120
|
||||
// f10, = 121
|
||||
// f11, = 122
|
||||
// f12, = 123
|
||||
// f13, = 124
|
||||
// f14, = 125
|
||||
// f15, = 126
|
||||
// f16, = 127
|
||||
// f17, = 128
|
||||
// f18, = 129
|
||||
// f19, = 130
|
||||
// f20, = 131
|
||||
// f21, = 132
|
||||
// f22, = 133
|
||||
// f23, = 134
|
||||
// f24, = 135
|
||||
// f25, = 136
|
||||
// f26, = 137
|
||||
// f27, = 138
|
||||
// f28, = 139
|
||||
// f29, = 140
|
||||
// f30, = 141
|
||||
// f31, = 142
|
||||
// f32, = 143
|
||||
// num lock, = 144
|
||||
// scroll lock, = 145
|
||||
// airplane mode, = 151
|
||||
// ^, = 160
|
||||
// !, = 161
|
||||
// ؛ (arabic semicolon), = 162
|
||||
// #, = 163
|
||||
// $, = 164
|
||||
// ù, = 165
|
||||
// page backward, = 166
|
||||
// page forward, = 167
|
||||
// refresh, = 168
|
||||
// closing paren (AZERTY), = 169
|
||||
// *, = 170
|
||||
// ~ + * key, = 171
|
||||
// home key, = 172
|
||||
// minus (firefox), mute/unmute, = 173
|
||||
// decrease volume level, = 174
|
||||
// increase volume level, = 175
|
||||
// next, = 176
|
||||
// previous, = 177
|
||||
// stop, = 178
|
||||
// play/pause, = 179
|
||||
// e-mail, = 180
|
||||
// mute/unmute (firefox), = 181
|
||||
// decrease volume level (firefox), = 182
|
||||
// increase volume level (firefox), = 183
|
||||
// semi-colon / ñ, = 186
|
||||
// equal sign, = 187
|
||||
// comma, = 188
|
||||
// dash, = 189
|
||||
// period, = 190
|
||||
// forward slash / ç, = 191
|
||||
// grave accent / ñ / æ / ö, = 192
|
||||
// ?, / or °, = 193
|
||||
// numpad period (chrome), = 194
|
||||
// open bracket, = 219
|
||||
// back slash, = 220
|
||||
// close bracket / å, = 221
|
||||
// single quote / ø / ä, = 222
|
||||
// `, = 223
|
||||
// left or right ⌘ key (firefox), = 224
|
||||
// altgr, = 225
|
||||
// < /git >, left back slash, = 226
|
||||
// GNOME Compose Key, = 230
|
||||
// ç, = 231
|
||||
// XF86Forward, = 233
|
||||
// XF86Back, = 234
|
||||
// non-conversion, = 235
|
||||
// alphanumeric, = 240
|
||||
// hiragana/katakana, = 242
|
||||
// half-width/full-width, = 243
|
||||
// kanji, = 244
|
||||
// unlock trackpad (Chrome/Edge), = 251
|
||||
// toggle touchpad, = 255
|
||||
NA = 0,
|
||||
Break = 3,
|
||||
Backspace = 8,
|
||||
Tab = 9,
|
||||
Clear = 12,
|
||||
Enter = 13,
|
||||
Shift = 16,
|
||||
Ctrl = 17,
|
||||
Alt = 18,
|
||||
Pause = 19,
|
||||
CapsLock = 20,
|
||||
// hangul, = 21
|
||||
// hanja, = 25
|
||||
Escape = 27,
|
||||
// conversion, = 28
|
||||
// non-conversion, = 29
|
||||
Space = 32,
|
||||
PageUp = 33,
|
||||
PageDown = 34,
|
||||
End = 35,
|
||||
Home = 36,
|
||||
LeftArrow = 37,
|
||||
UpArrow = 38,
|
||||
RightArrow = 39,
|
||||
DownArrow = 40,
|
||||
// select, = 41
|
||||
// print, = 42
|
||||
// execute, = 43
|
||||
// Print Screen, = 44
|
||||
Insert = 45,
|
||||
Delete = 46,
|
||||
// help, = 47
|
||||
Num0 = 48,
|
||||
Num1 = 49,
|
||||
Num2 = 50,
|
||||
Num3 = 51,
|
||||
Num4 = 52,
|
||||
Num5 = 53,
|
||||
Num6 = 54,
|
||||
Num7 = 55,
|
||||
Num8 = 56,
|
||||
Num9 = 57,
|
||||
// :, = 58
|
||||
// semicolon (firefox), equals, = 59
|
||||
// <, = 60
|
||||
// equals (firefox), = 61
|
||||
// ß, = 63
|
||||
// @ (firefox), = 64
|
||||
A = 65,
|
||||
B = 66,
|
||||
C = 67,
|
||||
D = 68,
|
||||
E = 69,
|
||||
F = 70,
|
||||
G = 71,
|
||||
H = 72,
|
||||
I = 73,
|
||||
J = 74,
|
||||
K = 75,
|
||||
L = 76,
|
||||
M = 77,
|
||||
N = 78,
|
||||
O = 79,
|
||||
P = 80,
|
||||
Q = 81,
|
||||
R = 82,
|
||||
S = 83,
|
||||
T = 84,
|
||||
U = 85,
|
||||
V = 86,
|
||||
W = 87,
|
||||
X = 88,
|
||||
Y = 89,
|
||||
Z = 90,
|
||||
LeftWindow = 91,
|
||||
RightWindow = 92,
|
||||
SelectKey = 93,
|
||||
Numpad0 = 96,
|
||||
Numpad1 = 97,
|
||||
Numpad2 = 98,
|
||||
Numpad3 = 99,
|
||||
Numpad4 = 100,
|
||||
Numpad5 = 101,
|
||||
Numpad6 = 102,
|
||||
Numpad7 = 103,
|
||||
Numpad8 = 104,
|
||||
Numpad9 = 105,
|
||||
Multiply = 106,
|
||||
Add = 107,
|
||||
Subtract = 109,
|
||||
DecimalPoint = 110,
|
||||
Divide = 111,
|
||||
F1 = 112,
|
||||
F2 = 113,
|
||||
F3 = 114,
|
||||
F4 = 115,
|
||||
F5 = 116,
|
||||
F6 = 117,
|
||||
F7 = 118,
|
||||
F8 = 119,
|
||||
F9 = 120,
|
||||
F10 = 121,
|
||||
F11 = 122,
|
||||
F12 = 123,
|
||||
// f13, = 124
|
||||
// f14, = 125
|
||||
// f15, = 126
|
||||
// f16, = 127
|
||||
// f17, = 128
|
||||
// f18, = 129
|
||||
// f19, = 130
|
||||
// f20, = 131
|
||||
// f21, = 132
|
||||
// f22, = 133
|
||||
// f23, = 134
|
||||
// f24, = 135
|
||||
// f25, = 136
|
||||
// f26, = 137
|
||||
// f27, = 138
|
||||
// f28, = 139
|
||||
// f29, = 140
|
||||
// f30, = 141
|
||||
// f31, = 142
|
||||
// f32, = 143
|
||||
NumLock = 144,
|
||||
ScrollLock = 145,
|
||||
// airplane mode, = 151
|
||||
// ^, = 160
|
||||
// !, = 161
|
||||
// ؛ (arabic semicolon), = 162
|
||||
// #, = 163
|
||||
// $, = 164
|
||||
// ù, = 165
|
||||
// page backward, = 166
|
||||
// page forward, = 167
|
||||
// refresh, = 168
|
||||
// closing paren (AZERTY), = 169
|
||||
// *, = 170
|
||||
// ~ + * key, = 171
|
||||
// home key, = 172
|
||||
// minus (firefox), mute/unmute, = 173
|
||||
// decrease volume level, = 174
|
||||
// increase volume level, = 175
|
||||
// next, = 176
|
||||
// previous, = 177
|
||||
// stop, = 178
|
||||
// play/pause, = 179
|
||||
// e-mail, = 180
|
||||
// mute/unmute (firefox), = 181
|
||||
// decrease volume level (firefox), = 182
|
||||
// increase volume level (firefox), = 183
|
||||
Semicolon = 186,
|
||||
EqualSign = 187,
|
||||
Comma = 188,
|
||||
Dash = 189,
|
||||
Period = 190,
|
||||
ForwardSlash = 191,
|
||||
GraveAccent = 192,
|
||||
// ?, / or °, = 193
|
||||
// numpad period (chrome), = 194
|
||||
OpenBracket = 219,
|
||||
BackSlash = 220,
|
||||
CloseBraket = 221,
|
||||
SingleQuote = 222,
|
||||
// `, = 223
|
||||
// left or right ⌘ key (firefox), = 224
|
||||
// altgr, = 225
|
||||
// < /git >, left back slash, = 226
|
||||
// GNOME Compose Key, = 230
|
||||
// ç, = 231
|
||||
// XF86Forward, = 233
|
||||
// XF86Back, = 234
|
||||
// non-conversion, = 235
|
||||
// alphanumeric, = 240
|
||||
// hiragana/katakana, = 242
|
||||
// half-width/full-width, = 243
|
||||
// kanji, = 244
|
||||
// unlock trackpad (Chrome/Edge), = 251
|
||||
// toggle touchpad, = 255
|
||||
#[cfg_attr(feature = "serialize", serde(other))]
|
||||
Unknown,
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
use js_sys::Function;
|
||||
use wasm_bindgen::prelude::*;
|
||||
use web_sys::{Element, Node};
|
||||
use web_sys::Element;
|
||||
|
||||
#[wasm_bindgen(module = "/src/interpreter.js")]
|
||||
extern "C" {
|
||||
@@ -18,7 +18,7 @@ extern "C" {
|
||||
pub fn MountToRoot(this: &Interpreter);
|
||||
|
||||
#[wasm_bindgen(method)]
|
||||
pub fn AppendChildren(this: &Interpreter, m: u32);
|
||||
pub fn AppendChildren(this: &Interpreter, m: u32, id: u32);
|
||||
|
||||
#[wasm_bindgen(method)]
|
||||
pub fn AssignId(this: &Interpreter, path: &[u8], id: u32);
|
||||
|
||||
@@ -40,7 +40,7 @@ async fn order_shoes(mut req: WebsocketRequest) -> Response {
|
||||
}
|
||||
|
||||
fn App(cx: Scope) -> Element {
|
||||
let mut count = use_state(&cx, || 0);
|
||||
let mut count = use_state(cx, || 0);
|
||||
cx.render(rsx!(
|
||||
button { onclick: move |_| count += 1, "Incr" }
|
||||
button { onclick: move |_| count -= 1, "Decr" }
|
||||
|
||||
@@ -6,7 +6,7 @@ use std::any::Any;
|
||||
use std::sync::Arc;
|
||||
|
||||
use dioxus_core::ElementId;
|
||||
use dioxus_html::event_bubbles;
|
||||
// use dioxus_html::event_bubbles;
|
||||
use dioxus_html::events::*;
|
||||
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
@@ -29,7 +29,7 @@ struct ImEvent {
|
||||
contents: serde_json::Value,
|
||||
}
|
||||
|
||||
pub fn trigger_from_serialized(val: serde_json::Value) -> () {
|
||||
pub fn trigger_from_serialized(_val: serde_json::Value) {
|
||||
todo!()
|
||||
// let ImEvent {
|
||||
// event,
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use anymap::AnyMap;
|
||||
use dioxus::prelude::*;
|
||||
use dioxus_native_core::node_ref::*;
|
||||
use dioxus_native_core::real_dom::*;
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
use dioxus::core::ElementId;
|
||||
use dioxus::core::{AttributeValue, Mutations};
|
||||
use dioxus::prelude::*;
|
||||
use dioxus_native_core::real_dom::*;
|
||||
use dioxus_native_core::state::{ChildDepState, NodeDepState, ParentDepState, State};
|
||||
use dioxus_native_core::tree::TreeView;
|
||||
use dioxus_native_core::{node_ref::*, NodeId, RealNodeId, SendAnyMap};
|
||||
use dioxus_native_core::{node_ref::*, NodeId, SendAnyMap};
|
||||
use dioxus_native_core_macro::State;
|
||||
|
||||
#[derive(Debug, Clone, Default, State)]
|
||||
|
||||
@@ -36,7 +36,9 @@ fn BlogList(cx: Scope) -> Element {
|
||||
}
|
||||
|
||||
fn BlogPost(cx: Scope) -> Element {
|
||||
let id = use_route(&cx).segment("id")?;
|
||||
let Some(id) = use_route(cx).segment("id") else {
|
||||
return cx.render(rsx! { div { "No blog post id" } })
|
||||
};
|
||||
|
||||
log::trace!("rendering blog post {}", id);
|
||||
|
||||
|
||||
@@ -39,15 +39,15 @@ pub struct RouterProps<'a> {
|
||||
/// Will fallback to HashRouter is BrowserRouter is not available, or through configuration.
|
||||
#[allow(non_snake_case)]
|
||||
pub fn Router<'a>(cx: Scope<'a, RouterProps<'a>>) -> Element {
|
||||
let svc = use_context_provider(cx, || {
|
||||
RouterService::new(
|
||||
let svc = cx.use_hook(|| {
|
||||
cx.provide_context(RouterService::new(
|
||||
cx,
|
||||
RouterCfg {
|
||||
base_url: cx.props.base_url.map(|s| s.to_string()),
|
||||
active_class: cx.props.active_class.map(|s| s.to_string()),
|
||||
initial_url: cx.props.initial_url.clone(),
|
||||
},
|
||||
)
|
||||
))
|
||||
});
|
||||
|
||||
// next time we run the rout_found will be filled
|
||||
|
||||
@@ -415,7 +415,7 @@ mod web {
|
||||
}
|
||||
}
|
||||
|
||||
fn attach_listeners(&self, svc: std::sync::Weak<crate::RouterService>) {
|
||||
fn attach_listeners(&self, svc: std::rc::Weak<crate::RouterService>) {
|
||||
self._listener.set(Some(EventListener::new(
|
||||
&web_sys::window().unwrap(),
|
||||
"popstate",
|
||||
|
||||
@@ -13,13 +13,13 @@ fn simple_test() {
|
||||
fn main() {
|
||||
console_error_panic_hook::set_once();
|
||||
wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
|
||||
dioxus_web::launch(APP);
|
||||
dioxus_web::launch(app);
|
||||
}
|
||||
|
||||
static APP: Component = |cx| {
|
||||
fn app(cx: Scope) -> Element {
|
||||
cx.render(rsx! {
|
||||
Router {
|
||||
onchange: move |route: RouterService| log::trace!("route changed to {:?}", route.current_location()),
|
||||
onchange: move |router: RouterContext| log::trace!("route changed to {:?}", router.current_location()),
|
||||
active_class: "is-active",
|
||||
Route { to: "/", Home {} }
|
||||
Route { to: "blog"
|
||||
@@ -28,7 +28,7 @@ fn simple_test() {
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
fn Home(cx: Scope) -> Element {
|
||||
cx.render(rsx! {
|
||||
@@ -47,12 +47,10 @@ fn simple_test() {
|
||||
}
|
||||
|
||||
fn BlogPost(cx: Scope) -> Element {
|
||||
let _id = use_route(&cx).parse_segment::<usize>("id")?;
|
||||
let _id = use_route(cx).parse_segment::<usize>("id").unwrap();
|
||||
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
|
||||
}
|
||||
div { }
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -109,7 +109,7 @@ For any route, you can get a handle the current route with the `use_route` hook.
|
||||
|
||||
```rust
|
||||
fn Title(cx: Scope) -> Element {
|
||||
let route = use_route(&cx);
|
||||
let route = use_route(cx);
|
||||
|
||||
assert_eq!(route.segments(), &["dogs", "breeds", "yorkie", "hugo"]);
|
||||
|
||||
@@ -130,7 +130,7 @@ Router {
|
||||
}
|
||||
|
||||
fn BlogPost(cx: Scope) -> Element {
|
||||
let route = use_route(&cx);
|
||||
let route = use_route(cx);
|
||||
|
||||
match route.segment("post").and_then(parse) {
|
||||
Some(post) => cx.render(rsx!{ div { "Post {post}" } })
|
||||
@@ -168,7 +168,7 @@ Listeners can also be attached downstream in your app with the `RouteListener` h
|
||||
|
||||
```rust
|
||||
fn TitleCard(cx: Scope) -> Element {
|
||||
let (title, set_title) = use_state(&cx, || "First");
|
||||
let (title, set_title) = use_state(cx, || "First");
|
||||
|
||||
cx.render(rsx!{
|
||||
h1 { "render {title}" }
|
||||
|
||||
@@ -192,16 +192,16 @@ impl ToTokens for Element {
|
||||
|
||||
#[derive(PartialEq, Eq, Clone, Debug, Hash)]
|
||||
pub enum ElementAttr {
|
||||
/// attribute: "valuee {}"
|
||||
/// `attribute: "value"`
|
||||
AttrText { name: Ident, value: IfmtInput },
|
||||
|
||||
/// attribute: true,
|
||||
/// `attribute: true`
|
||||
AttrExpression { name: Ident, value: Expr },
|
||||
|
||||
/// "attribute": "value {}"
|
||||
/// `"attribute": "value"`
|
||||
CustomAttrText { name: LitStr, value: IfmtInput },
|
||||
|
||||
/// "attribute": true,
|
||||
/// `"attribute": true`
|
||||
CustomAttrExpression { name: LitStr, value: Expr },
|
||||
|
||||
// /// onclick: move |_| {}
|
||||
|
||||
@@ -199,8 +199,8 @@ impl<'a> DynamicContext<'a> {
|
||||
let value = value.source.as_ref().unwrap();
|
||||
quote! {
|
||||
::dioxus::core::TemplateAttribute::Static {
|
||||
name: dioxus_elements::#el_name::#name.0,
|
||||
namespace: dioxus_elements::#el_name::#name.1,
|
||||
name: #name,
|
||||
namespace: None,
|
||||
value: #value,
|
||||
|
||||
// todo: we don't diff these so we never apply the volatile flag
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use dioxus_core::prelude::*;
|
||||
use std::fmt::Write;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct StringCache {
|
||||
pub segments: Vec<Segment>,
|
||||
pub template: Template<'static>,
|
||||
|
||||
@@ -156,26 +156,29 @@ fn to_string_works() {
|
||||
_ = dom.rebuild();
|
||||
|
||||
let mut renderer = Renderer::new();
|
||||
|
||||
let out = renderer.render(&dom);
|
||||
|
||||
use Segment::*;
|
||||
assert_eq!(
|
||||
renderer.template_cache.iter().next().unwrap().1.segments,
|
||||
vec![
|
||||
PreRendered("<div class=\"asdasdasd\" class=\"asdasdasd\"".into(),),
|
||||
Attr(0,),
|
||||
PreRendered(">Hello world 1 -->".into(),),
|
||||
Node(0,),
|
||||
PreRendered("<-- Hello world 2<div>nest 1</div><div></div><div>nest 2</div>".into(),),
|
||||
Node(1,),
|
||||
Node(2,),
|
||||
PreRendered("</div>".into(),),
|
||||
]
|
||||
);
|
||||
for item in renderer.template_cache.iter() {
|
||||
if item.1.segments.len() > 5 {
|
||||
assert_eq!(
|
||||
item.1.segments,
|
||||
vec![
|
||||
PreRendered("<div class=\"asdasdasd\" class=\"asdasdasd\"".into(),),
|
||||
Attr(0,),
|
||||
PreRendered(">Hello world 1 -->".into(),),
|
||||
Node(0,),
|
||||
PreRendered(
|
||||
"<-- Hello world 2<div>nest 1</div><div></div><div>nest 2</div>".into(),
|
||||
),
|
||||
Node(1,),
|
||||
Node(2,),
|
||||
PreRendered("</div>".into(),),
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
out,
|
||||
"<div class=\"asdasdasd\" class=\"asdasdasd\" id=\"id-123\">Hello world 1 --><!--#-->123<!--/#--><-- Hello world 2<div>nest 1</div><div></div><div>nest 2</div><!--#--></diiiiiiiiv><!--/#--><div><!--#-->finalize 0<!--/#--></div><div><!--#-->finalize 1<!--/#--></div><div><!--#-->finalize 2<!--/#--></div><div><!--#-->finalize 3<!--/#--></div><div><!--#-->finalize 4<!--/#--></div></div>"
|
||||
);
|
||||
use Segment::*;
|
||||
|
||||
assert_eq!(out, "<div class=\"asdasdasd\" class=\"asdasdasd\" id=\"id-123\">Hello world 1 -->123<-- Hello world 2<div>nest 1</div><div></div><div>nest 2</div></diiiiiiiiv><div>finalize 0</div><div>finalize 1</div><div>finalize 2</div><div>finalize 3</div><div>finalize 4</div></div>");
|
||||
}
|
||||
@@ -41,7 +41,7 @@ struct BoxProps {
|
||||
}
|
||||
#[allow(non_snake_case)]
|
||||
fn Box(cx: Scope<BoxProps>) -> Element {
|
||||
let count = use_state(&cx, || 0);
|
||||
let count = use_state(cx, || 0);
|
||||
|
||||
let x = cx.props.x * 2;
|
||||
let y = cx.props.y * 2;
|
||||
@@ -70,8 +70,8 @@ struct GridProps {
|
||||
#[allow(non_snake_case)]
|
||||
fn Grid(cx: Scope<GridProps>) -> Element {
|
||||
let size = cx.props.size;
|
||||
let count = use_state(&cx, || 0);
|
||||
let counts = use_ref(&cx, || vec![0; size * size]);
|
||||
let count = use_state(cx, || 0);
|
||||
let counts = use_ref(cx, || vec![0; size * size]);
|
||||
|
||||
let ctx: &TuiContext = cx.consume_context().unwrap();
|
||||
if *count.get() + 1 >= (size * size) {
|
||||
|
||||
@@ -27,7 +27,7 @@ enum Event {
|
||||
const MAX_EVENTS: usize = 8;
|
||||
|
||||
fn app(cx: Scope) -> Element {
|
||||
let events = use_ref(&cx, Vec::new);
|
||||
let events = use_ref(cx, Vec::new);
|
||||
|
||||
let events_lock = events.read();
|
||||
let first_index = events_lock.len().saturating_sub(MAX_EVENTS);
|
||||
|
||||
@@ -5,7 +5,7 @@ fn main() {
|
||||
}
|
||||
|
||||
fn app(cx: Scope) -> Element {
|
||||
let radius = use_state(&cx, || 0);
|
||||
let radius = use_state(cx, || 0);
|
||||
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
|
||||
Loaded 100 of 113 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user