Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ members = [
"packages/playwright-tests/barebones-template",
"packages/playwright-tests/fullstack",
"packages/playwright-tests/fullstack-mounted",
"packages/playwright-tests/fullstack-spread",
"packages/playwright-tests/fullstack-routing",
"packages/playwright-tests/suspense-carousel",
"packages/playwright-tests/nested-suspense",
Expand Down
6 changes: 5 additions & 1 deletion packages/core/src/diff/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -819,10 +819,14 @@ impl VNode {
}
};

// Write the value for each attribute in the group
for attr in &**attribute {
self.write_attribute(attribute_path, attr, id, mount, dom, to);
dom.set_mounted_dyn_attr(mount, attribute_idx, id);
}
// Set the mounted dynamic attribute once. This must be set even if no actual
// attributes are present so it is present for renderers like fullstack to look
// up the position where attributes may be inserted in the future
dom.set_mounted_dyn_attr(mount, attribute_idx, id);
}
}

Expand Down
13 changes: 13 additions & 0 deletions packages/playwright-tests/fullstack-spread.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// @ts-check
const { test, expect } = require("@playwright/test");

test("spread attributes hydrate", async ({ page }) => {
await page.goto("http://localhost:7979");

// Expect the page to contain the button
const counter = page.locator("#counter");
await expect(counter).toHaveText("Count: 0");
// Clicking on the button should increment the count
await counter.click();
await expect(counter).toHaveText("Count: 1");
});
15 changes: 15 additions & 0 deletions packages/playwright-tests/fullstack-spread/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[package]
name = "dioxus-playwright-fullstack-spread-test"
version = "0.1.0"
edition = "2021"
publish = false

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
dioxus = { workspace = true, features = ["fullstack"] }

[features]
default = []
server = ["dioxus/server"]
web = ["dioxus/web"]
40 changes: 40 additions & 0 deletions packages/playwright-tests/fullstack-spread/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//! Regression test for <https://github.com/DioxusLabs/dioxus/issues/4646>

use dioxus::prelude::*;

fn main() {
dioxus::launch(|| {
rsx! {
Comp {}
Comp {}
Button {}
}
});
}

#[component]
fn Button() -> Element {
let mut count = use_signal(|| 0);

rsx! {
button {
id: "counter",
onclick: move |_| {
count += 1;
},
"Count: {count}"
}
}
}

#[component]
fn Comp(#[props(extends = GlobalAttributes)] attributes: Vec<Attribute>) -> Element {
rsx! {
div {
width: 100,
div {
..attributes,
}
}
}
}
9 changes: 9 additions & 0 deletions packages/playwright-tests/playwright.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,15 @@ module.exports = defineConfig({
reuseExistingServer: !process.env.CI,
stdout: "pipe",
},
{
cwd: path.join(process.cwd(), "fullstack-spread"),
command:
'cargo run --package dioxus-cli --release -- run --verbose --force-sequential --web --addr "127.0.0.1" --port 7979',
port: 7979,
timeout: 50 * 60 * 1000,
reuseExistingServer: !process.env.CI,
stdout: "pipe",
},
{
cwd: path.join(process.cwd(), "fullstack-routing"),
command:
Expand Down
5 changes: 4 additions & 1 deletion packages/web/src/hydration/hydrate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,9 +301,12 @@ impl WebsysDom {
let id = vnode
.mounted_dynamic_attribute(*id, dom)
.ok_or(VNodeNotInitialized)?;
// We always need to hydrate the node even if the attributes are empty so we have
// a mount for the node later. This could be spread attributes that are currently empty,
// but will be filled later
mounted_id = Some(id);
for attribute in attributes {
let value = &attribute.value;
mounted_id = Some(id);
if let AttributeValue::Listener(_) = value {
if attribute.name == "onmounted" {
to_mount.push(id);
Expand Down
Loading