inertia
inertia copied to clipboard
event listeners are not attached to HTML markup after SSR (hydrateRoot)
Versions:
@inertiajs/inertiaversion: 0.11.1@inertiajs/inertia-reactversion: 0.8.1
Describe the problem:
The javascript event listeners are not attached to the HTML even after hydrating.
Example: let's assume there is an event handler registered for an input field named name. Whenever the user changes the value in the text field, the event listeners should fire.
Steps to reproduce:
Reproduction repository: https://github.com/awkward-minion/inertiajs-react-form-handlers.git
Step 1: Add SSR integration for your server
Below is my SSR integration, with this the client (browser) was able to receive plain HTML markup with no javascript code (in the response as expected).
import React from 'react'
import ReactDOMServer from 'react-dom/server'
import { createInertiaApp } from '@inertiajs/inertia-react'
import createServer from '@inertiajs/server'
const pages = import.meta.glob('../pages/*.tsx')
async function resolvePage(name: string) {
const page = pages[`../pages/${name}.tsx`] as any
const importedModule = page
const pageComponent = (await importedModule()).default
return pageComponent
}
const cb = (page) => createInertiaApp({
page,
render: ReactDOMServer.renderToString,
resolve: resolvePage,
setup: ({ App, props }) => <App {...props} />,
})
createServer(cb)
Step 2: hydrate your SSR page on the client side using hydrateRoot
And I am trying to hydrate it on the client side, using the below code
import React from "react";
import { hydrateRoot } from "react-dom/client";
import { createInertiaApp } from "@inertiajs/inertia-react";
const pages: any = import.meta.glob("../pages/*.tsx");
const opts = {
resolve: async (name) => {
const page = (await pages[`../pages/${name}.tsx`]());
return page.default;
},
setup({ el, App, props }) {
const container = document.getElementById(el.id);
const root = hydrateRoot(container, <App {...props} />);
},
};
document.addEventListener("DOMContentLoaded", () => {
createInertiaApp(opts);
});
Step 3: A simple component that illustrates the problem
This is where javascript handlers are not being attached to DOM after hydration
I have a form component let's say NewUser.tsx
import { Inertia } from "@inertiajs/inertia";
const NewUser = () => {
const [values, setValues] = useState({name: ""});
function handleChange(e) {
console.log("value changing", e.target.value);
setValues((values) => ({
...values,
[e.target.id]: e.target.value,
}));
}
function handleSubmit(e) {
Inertia.post("/register", values);
}
return (
<form onSubmit={handleSubmit}>
<input id="name" value={values.name} onChange={handleChange} />
<button type="submit">Submit</button>
</form>
);
};
export default NewUser;
Reproduction repository: https://github.com/awkward-minion/inertiajs-react-form-handlers.git
The browser renders this problem without any issues.
But the event handlers like handleSubmit and handleChange are not registered after the hydration.
Observations
- SSR is properly generating HTML markup along with layout
- Client-side
hydrateRootwas not displaying any warnings, considering it as good. The javascriptbundleis being loaded in the browser. (the event handlers) - Problem - the event handlers are not bonded