styled-components
should not result in the className
mismatch warning from React.
Warning: Prop `className` did not match. Server: "Header-johx6c-0 bHIeEO" Client: "Header___default-johx6c-0 gGUBlx"
I'm exporting the header component like so:
export default styled(Header)`
text-align: center;
`;
Notice that styled-components
uses the name Header
on the server and Header__default
on the client. This doesn't happen with Next.js 4, so I assume it has something to do with the way modules are built with the new Universal Webpack setup.
styled-components
with next
v5.babel-plugin-styled-components
with the default displayName
setting.export default styled(Component)
(It doesn't matter what the Babel plugin's ssr
setting is, nor if the server stylesheet is set up in _document.js
. Same thing in every combination.)
| Tech | Version |
|---------|---------|
| next | v5.0.0 |
| node | v8.9.4 |
| OS | macOS |
| browser | Chrome |
bump.
It only happens in dev for me though.
Tim knows this and said its on their list of things todo very soon!
I got the same problem with a simple h1 component:
const Headline = styled.h1`...`;
Warning: Prop `className` did not match. Server: "pages__Headline-te1id5-0 bqAPoZ" Client: "pages__Headline-te1id5-0 cIpCqj"
Also only for dev...
Tim knows this and said its on their list of things todo very soon!
I haven't said anything like this at any point 🤔
Maybe @kitten knows what's going on.
I suppose this is a side effect of using ES module exports for the client and CJS for the server, correct?
I thought we used to have a fix for this in place but apparently we don’t. I’m not sure how safe it’d be to filter out component names that are exposed as “default” but that’d be a solution.
Please note that I would not recommend the “export default styled.div” pattern. I’d guess this is what causes this.
As the result you’d get when applying the above to arrow functions, similarly for our Babel plugin this would mean that your StyledComponent technically doesn’t have a name. So simply writing “const X = ...; export default X” might help here if I’m not mistaken. Even if for “Header” you’d name that variable “Header” or “Container”, for debugging in general this would be more explicit.
Finally got a fix for this issue. You need to specify for each environment how babel handles styled-components:
this is my .babelrc file, I have other stuff going on in here but look specifically at "Development". Adding the development under env should fix the error completely.
{
"env": {
"test": {
"presets": [
[
"env",
{
"modules": "commonjs"
}
],
"next/babel"
]
},
"development": {
"plugins": [
[
"styled-components",
{
"ssr": true,
"displayName": true
}
]
],
"presets": "next/babel"
},
"production": {
"presets": "next/babel"
},
"server": {
"presets": [
[
"env",
{
"modules": "commonjs"
}
],
"next/babel"
]
}
},
"plugins": [
[
"styled-components",
{
"ssr": true,
"displayName": true
}
],
[
"inline-react-svg"
],
[
"transform-flow-strip-types"
]
],
"retainLines": true
}
@spencersmb alright, this indicates that the recommended next.js usage of the plugin is out of date. We've got a note on why this matters in our docs https://www.styled-components.com/docs/tooling#usage
Quote:
The plugin call order in your .babelrc file matters. If you're using the env property in your babel configuration, then putting this plugin into the plugins array won't suffice. Instead it needs to be put into each env's plugins array to maintain it being executed first. See this for more information.
With this issue linked there: https://github.com/styled-components/babel-plugin-styled-components/issues/78
The next.js example needs an update then, if I'm not mistaken? :smile:
@kitten makes sense. The example is actually fine since it doesn't use "env"
maybe this should be documented in the example readme though 🤔
https://github.com/zeit/next.js/blob/canary/examples/with-styled-components/
https://github.com/zeit/next.js/blob/canary/examples/with-styled-components/.babelrc
Hmmm, I don't use different envs in my .baberc (actually it looks like the one Tim referenced) and I don't export the styled component. I just use it in the same file:
const Test = styled.div`
color: red;
`;
export default () => (
<>
...
<Test>XXX</Test>
...
</>
);
Strangely enough it happens only on my index page and not on every page load...
Hiya, I am also getting Warning: Prop className
did not match. Server: "sc-ifAKCX jWHVsk" Client: "sc-bdVaJa ebJbtP"
I was npm link components
into my nextJS project and this was causing the issue I think. When I bring the component into the project without linking it works, I still get the render flash though.
Also the issue seems to be on a full refresh - when I edit the page the element renders correctly, on full refresh I get the error above again
Hope this helps to dive a little deeper
Babelrc
{
"plugins": [
[ "styled-components", { "ssr": true, "displayName": true, "preprocess": false } ],
],
"presets": ["next/babel"]
}
I use style inline method
const Button = styled.button`
border: none;
border-radius: 5rem;
color: white;
cursor: pointer;
display: inline-block;
font-size: 1rem;
`
I'm assuming this doesn't happen anymore with latest styled-components.
@timneutkens Actually it still happens. Is it just me or do you guys also still have this warning popping up?
I'm using [email protected]
and [email protected]
.
Any update on this issue ? Seems annoying to everyone using in dev mode.
What about the Babel plugin version @sarneeh @revskill10? I just tried to make a quick repro with the latest version of next
, styled-components
, and babel-plugin-styled-components
and it looks fixed to me. __default
isn't appended to the computed name of the exported component anymore.
@exogen I'm using "babel-plugin-macros": "^2.4.2",
, with antd
and always got this warning.
The magic is Why client-side still generates their own IDs , because as i see, the only place to generate IDs is in _document.js
, which only happens on server side though.
These are my versions:
next 7.0.2
babel-plugin-styled-components 1.1.5
styled-components 4.1.3
...and I'm still having this issue intermittently. Any suggestions?
I found this to work. Make sure you have babel-plugin-styled-components
in your dependencies. The following can go in .babelrc or in package.json
```
"babel": {
"env": {
"development": {
"presets": ["next/babel"],
"plugins": [
["styled-components", {
"ssr": true,
"displayName": true
}]
]
},
"production": {
"presets": ["next/babel"],
"plugins": [
["styled-components", {
"ssr": true,
"displayName": true
}]
]
},
"test": {
"presets": [
["next/babel", {
"preset-env": {
"modules": "commonjs"
}
}]
],
"plugins": [
["styled-components", {
"ssr": true,
"displayName": true
}]
]
}
}
}
Issue also occurs with react-jss, where no babel plugin is required.
When the server starts everything works fine, then …randomly… if I refresh the page or hot-reloading does it, client rendered className (example: Comp-el-0-1-3
) is higher of server rendered className (example: Comp-el-0-1-1
). 🤷‍♂️
next: 8.0.3
react-jss: 8.6.1
@babel/core: 7.3.3
For me everything is fine in production but I get a warning for className mismatch in development. I quickly solved the issue by disabling stylesheets server-side rendering in development.
Here is my _document
class MyDocument extends Document {
static async getInitialProps(ctx) {
const sheet = new ServerStyleSheet();
const originalRenderPage = ctx.renderPage;
try {
const initialProps = await Document.getInitialProps(ctx);
// prevent stylesheets server-side rendering
// in case we are not in production
if (!process.env.NODE_ENV !== 'production') {
return initialProps;
}
ctx.renderPage = () =>
originalRenderPage({
enhanceApp: App => props => sheet.collectStyles(<App {...props} />),
});
return {
...initialProps,
styles: (
<React.Fragment>
{initialProps.styles}
{sheet.getStyleElement()}
</React.Fragment>
),
};
} finally {
sheet.seal();
}
}
}
Then you just to have to edit your babel config to disable the ssr
option in development (note that if you're using a .babelrc
file to manage babel's config you'll have to convert it to a .babelrc.js
file)
const dev = process.env.NODE_ENV !== 'production';
module.exports = {
presets: ['next/babel'],
plugins: [
['styled-components', { ssr: !dev, displayName: dev }],
],
};
Most helpful comment
I suppose this is a side effect of using ES module exports for the client and CJS for the server, correct?
I thought we used to have a fix for this in place but apparently we don’t. I’m not sure how safe it’d be to filter out component names that are exposed as “default” but that’d be a solution.
Please note that I would not recommend the “export default styled.div” pattern. I’d guess this is what causes this.
As the result you’d get when applying the above to arrow functions, similarly for our Babel plugin this would mean that your StyledComponent technically doesn’t have a name. So simply writing “const X = ...; export default X” might help here if I’m not mistaken. Even if for “Header” you’d name that variable “Header” or “Container”, for debugging in general this would be more explicit.