From d890cc72ac4c616d3c37332ce7695528d44fef84 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Tue, 7 Jan 2025 21:52:27 -0600 Subject: [PATCH] Fix mounted event after initial hydration (#3480) * trigger queued mounted events immediately after hydrating * add a playwright test to prevent regressions --- Cargo.lock | 9 ++++++++ Cargo.toml | 1 + .../fullstack-mounted.spec.js | 10 ++++++++ .../fullstack-mounted/Cargo.toml | 17 ++++++++++++++ .../fullstack-mounted/src/main.rs | 23 +++++++++++++++++++ .../playwright-tests/playwright.config.js | 9 ++++++++ packages/web/src/lib.rs | 6 +++++ packages/web/src/mutations.rs | 2 +- 8 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 packages/playwright-tests/fullstack-mounted.spec.js create mode 100644 packages/playwright-tests/fullstack-mounted/Cargo.toml create mode 100644 packages/playwright-tests/fullstack-mounted/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 2e4f1da81..5f46abda7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4026,6 +4026,15 @@ dependencies = [ "once_cell", ] +[[package]] +name = "dioxus-playwright-fullstack-mounted-test" +version = "0.1.0" +dependencies = [ + "dioxus", + "serde", + "tokio", +] + [[package]] name = "dioxus-playwright-fullstack-test" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index f62f32bda..90785ceda 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -97,6 +97,7 @@ members = [ "packages/playwright-tests/liveview", "packages/playwright-tests/web", "packages/playwright-tests/fullstack", + "packages/playwright-tests/fullstack-mounted", "packages/playwright-tests/suspense-carousel", "packages/playwright-tests/nested-suspense", ] diff --git a/packages/playwright-tests/fullstack-mounted.spec.js b/packages/playwright-tests/fullstack-mounted.spec.js new file mode 100644 index 000000000..03d2c709c --- /dev/null +++ b/packages/playwright-tests/fullstack-mounted.spec.js @@ -0,0 +1,10 @@ +// @ts-check +const { test, expect } = require("@playwright/test"); + +test("hydration", async ({ page }) => { + await page.goto("http://localhost:7777"); + + // Expect the page to contain the pending text. + const main = page.locator("#main"); + await expect(main).toContainText("The mounted event was triggered."); +}); diff --git a/packages/playwright-tests/fullstack-mounted/Cargo.toml b/packages/playwright-tests/fullstack-mounted/Cargo.toml new file mode 100644 index 000000000..e2187783b --- /dev/null +++ b/packages/playwright-tests/fullstack-mounted/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "dioxus-playwright-fullstack-mounted-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"] } +serde = "1.0.159" +tokio = { workspace = true, features = ["full"], optional = true } + +[features] +default = [] +server = ["dioxus/server", "dep:tokio"] +web = ["dioxus/web"] diff --git a/packages/playwright-tests/fullstack-mounted/src/main.rs b/packages/playwright-tests/fullstack-mounted/src/main.rs new file mode 100644 index 000000000..14e8f4846 --- /dev/null +++ b/packages/playwright-tests/fullstack-mounted/src/main.rs @@ -0,0 +1,23 @@ +// Regression test for https://github.com/DioxusLabs/dioxus/pull/3480 + +use dioxus::prelude::*; + +fn main() { + dioxus::launch(App); +} + +#[component] +fn App() -> Element { + let mut mounted = use_signal(|| false); + + rsx! { + div { + onmounted: move |_| { + mounted.set(true); + }, + if mounted() { + "The mounted event was triggered." + } + } + } +} diff --git a/packages/playwright-tests/playwright.config.js b/packages/playwright-tests/playwright.config.js index 522999b36..9fd8ff0f7 100644 --- a/packages/playwright-tests/playwright.config.js +++ b/packages/playwright-tests/playwright.config.js @@ -102,6 +102,15 @@ module.exports = defineConfig({ reuseExistingServer: !process.env.CI, stdout: "pipe", }, + { + cwd: path.join(process.cwd(), "fullstack-mounted"), + command: + 'cargo run --package dioxus-cli --release -- serve --force-sequential --platform web --addr "127.0.0.1" --port 7777', + port: 7777, + timeout: 50 * 60 * 1000, + reuseExistingServer: !process.env.CI, + stdout: "pipe", + }, { cwd: path.join(process.cwd(), "suspense-carousel"), command: diff --git a/packages/web/src/lib.rs b/packages/web/src/lib.rs index 2ebeed57e..3ad1290cd 100644 --- a/packages/web/src/lib.rs +++ b/packages/web/src/lib.rs @@ -125,6 +125,12 @@ pub async fn run(mut virtual_dom: VirtualDom, web_config: Config) -> ! { let rx = websys_dom.rehydrate(&virtual_dom).unwrap(); hydration_receiver = Some(rx); + + #[cfg(feature = "mounted")] + { + // Flush any mounted events that were queued up while hydrating + websys_dom.flush_queued_mounted_events(); + } } #[cfg(not(feature = "hydrate"))] { diff --git a/packages/web/src/mutations.rs b/packages/web/src/mutations.rs index b0c2b7e84..dd3b9028e 100644 --- a/packages/web/src/mutations.rs +++ b/packages/web/src/mutations.rs @@ -59,7 +59,7 @@ impl WebsysDom { } #[cfg(feature = "mounted")] - fn flush_queued_mounted_events(&mut self) { + pub(crate) fn flush_queued_mounted_events(&mut self) { for id in self.queued_mounted_events.drain(..) { let node = self.interpreter.base().get_node(id.0 as u32); if let Some(element) = node.dyn_ref::() {