Closed jmlee2k closed 4 months ago
For this particular case I have an idea. This looks like a JSON.stringify issue where remix loader data is stringified. You have "undefined" keys in your data. {disabled: undefined}, JSON.stringify makes them {disabled:null}, since "undefined" is not allowed in JSON objects. It is not a value, but null is a value. Your client mounts the component with the disabled property = true in he first render (most probably). Solution may be to make loader know in advance that the prop should be true but not undefined.
Edit: I just saw your sandbox. You dont use loader here but the issue is most probably some kind of "react server rendering of props with undefined values" thing.
@cakirlarc - yeah, I came to the same conclusion, but the weird part is that it changes depending on the browser and state of the cache - it works in chrome all the time, and works in firefox with a clear cache.
It seems like a timing issue to me, but I'm not familiar enough with Remix or SSR in general to have anything more than a hunch.
This looks like some sort of Firefox issue with maintaining client side state on soft reloads. I can reproduce the same error in a super basic React SSR setup. The issue seems to be a soft reload after the useEffect
has fired to enable the button. I changed the timeout to 2.5 seconds in my example - soft reloads within that 2.5 second window do not have the error. Once the button enables, the hydration issue arises on soft reloads.
Add the following to an index.mjs
file and run node index.mjs
.
import http from "node:http";
import * as React from "react";
import * as ReactDOMServer from "react-dom/server";
function App() {
let [disabled, setDisabled] = React.useState(true);
React.useEffect(() => {
setTimeout(() => setDisabled(false), 2500);
}, []);
return React.createElement(
"html",
null,
React.createElement(
"head",
null,
React.createElement(
"style",
null,
"button { border: 2px solid green; } " +
"button[disabled] { border: 2px solid red; }"
)
),
React.createElement(
"body",
null,
React.createElement("button", { disabled: disabled }, "Hello Button"),
React.createElement("script", {
crossOrigin: "true",
src: "https://unpkg.com/react@18.2.0/umd/react.development.js",
}),
React.createElement("script", {
crossOrigin: "true",
src: "https://unpkg.com/react-dom@18.2.0/umd/react-dom.development.js",
}),
React.createElement("script", {
async: "async",
dangerouslySetInnerHTML: {
__html:
App.toString() +
"\n" +
"ReactDOM.hydrateRoot(document, React.createElement(App));",
},
})
)
);
}
let server = http.createServer((req, res) => {
let doc = ReactDOMServer.renderToString(React.createElement(App));
res.setHeader("Content-Type", "text/html");
res.write("<!DOCTYPE html>" + doc);
res.end();
});
server.listen(3000, () => {
console.log("server listening on http://localhost:3000");
});
I need to log off for the day but I think this likely needs to get logged on the Firefox bug tracker, or maybe search through the React repo a bit and see if it's been encountered there before.
I logged https://bugzilla.mozilla.org/show_bug.cgi?id=1847798 to see if this is a Firefox bug
I have similar error when add Google AdSense snippet
<script async
src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=c-xxxxxxxxxx"
crossOrigin="anonymous"></script>
Prop `async` did not match. Server: "null" Client: "true"
I'm going to close this out as there's nothing Remix can really do about it.
Furthermore, the bug I filed 9 months ago was just marked as a duplicate of another bug opened 13 years ago 😨 ... so I'm no longer confident we'll see any traction.
In reading through the other bug I did find that this has come up enough that the difference in behavior from Firefox and all other browsers has made it's way onto MDN input
docs and can apparently be controlled in firefox using the autocomplete
attribute (search for firefox on the page if the hash link doesn't work).
What version of Remix are you using?
1.7.6
Steps to Reproduce
https://codesandbox.io/s/remix-prop-bug-g1hn4p?file=/app/routes/index.tsx
open codepen in new window
when reloading the codepen (in a new window) in Firefox with a primed cache, you'll see the error:
when bypassing the cache (shift+reload), there are no errors, and the page renders as expected.
interestingly, this seems to only happen in Firefox, chrome acts as expected regardless of the cache.
Expected Behavior
props should match on client and server
Actual Behavior
Warning: Prop "disabled" did not match. Server: "null" Client: "true"