Next.js 和 Styled Components 在刷新时服务器和客户端之间不同步

Posted

技术标签:

【中文标题】Next.js 和 Styled Components 在刷新时服务器和客户端之间不同步【英文标题】:Next.js and Styled Components go out of sync between the server and the client on refresh 【发布时间】:2021-02-20 17:23:09 【问题描述】:

我有一个使用样式化组件的 Next.js 应用程序。在第一次加载任何页面时,没有任何投诉,并且所有内容看起来都样式正确。但是,当我刷新页面时,一切看起来仍然正常,但我收到控制台错误读数:

Warning: Prop `className` did not match. Server: "sc-TXQaF bfnBGK" Client: "sc-bdnylx kKokSB"

我已尝试简化特定组件的样式,但错误仍然存​​在。我尝试从 DOM 中完全删除该组件,这会导致 DOM 中的下一个元素出现相同的错误。所以这似乎是一个全球性的问题。

我已按照此处找到的使用 Next.js 和样式化组件的指南进行操作:https://github.com/vercel/next.js/tree/master/examples/with-styled-components

我在根目录中有.babelrc 文件:


  "presets": ["next/babel"],
  "plugins": [["styled-components",  "s-s-r": true ]]

我的 pages 目录中有 _document.js 文件:

import Document from 'next/document'
import  ServerStyleSheet  from 'styled-components'

export default class MyDocument extends Document 
    static async getInitialProps(ctx) 
        const sheet = new ServerStyleSheet()
        const originalRenderPage = ctx.renderPage

        try 
            ctx.renderPage = () =>
                originalRenderPage(
                    enhanceApp: (App) => (props) =>
                        sheet.collectStyles(<App ...props />),
                )

            const initialProps = await Document.getInitialProps(ctx)
            return 
                ...initialProps,
                styles: (
                    <>
                        initialProps.styles
                        sheet.getStyleElement()
                    </>
                ),
            
         finally 
            sheet.seal()
        
    

这是我的样式组件之一的示例:

import styled from 'styled-components';

export const Block = styled.div`
margin: $props => props.small ? '2rem 0' : '4rem 0';
margin-top: $props => props.clearTop ? '0' : null;
`;

...尽管我尝试将其简化为像这样简单的事情,而控制台错误没有改变:

import styled from 'styled-components';

export const Block = styled.div`
position: relative;
`;

最后,这是一个仍然产生错误的愚蠢页面:

import  useContext, useEffect  from 'react';
import  useRouter  from 'next/router';

import Layout from '../components/layout';
import  Block  from '../components/styled/Block';

import  userContext  from '../context/userContext';;

function Profile() 

  const router = useRouter();

  const  loggedIn  = useContext(userContext);

  useEffect(() => 
    if (!loggedIn) router.push('/login');
  , [loggedIn]);

  return (
    <Layout>
      <Block>
        <h1>Test</h1>
      </Block>
    </Layout>
  )



export default Profile;

我的智慧到此为止。

【问题讨论】:

【参考方案1】:

我相信我找到了答案。我没有 babel 样式组件的 dev 依赖项。

npm install babel-plugin-styled-components --save-dev

你的package.json 文件应该有这个:

"devDependencies": 
  "babel-plugin-styled-components": "^1.11.1"

安装后,连同_document.js.babelrc 文件正确放置在您的应用中,您应该不会有任何问题。

【讨论】:

【参考方案2】:

我在过去 1 个月里遇到了这个问题,终于找到了适合我的解决方案!

所以这里的解决方案是只从服务器获取样式。

from the docs:

基本上你需要添加一个自定义页面/_document.js(如果你不 有一个)。然后复制样式组件的逻辑以注入 服务器端渲染样式到&lt;head&gt;

要解决此问题,您需要在 Document 组件中添加类似内容:

import Document from 'next/document'
import  ServerStyleSheet  from 'styled-components'

export default class MyDocument extends Document 
    static async getInitialProps(ctx) 

    const sheet = new ServerStyleSheet()
    const originalRenderPage = ctx.renderPage

    try 
      ctx.renderPage = () =>
        originalRenderPage(
          enhanceApp: (App) => (props) =>
            sheet.collectStyles(<App ...props />),
        )

      const initialProps = await Document.getInitialProps(ctx)
      return 
        ...initialProps,
        styles: (
          <>
            initialProps.styles
            sheet.getStyleElement()
          </>
        ),
      
     finally 
      sheet.seal()
    
  

最后一步(如果错误仍然存​​在)是删除缓存:删除 .next 文件夹并重新启动服务器

Next 文档中的完整示例代码是 Here

【讨论】:

以上是关于Next.js 和 Styled Components 在刷新时服务器和客户端之间不同步的主要内容,如果未能解决你的问题,请参考以下文章

是否有可能使用 Next.js + Styled-Components 和静态主机(例如 S3)制定有意义/安全的内容安全策略

在next.js中使用styled-component以及全局主题切换

在 Next.js 中为 styled-jsx 动态添加样式

如何在 Next.js 的活动页面上设置链接组件的样式

如何将 Nextjs + styled-components 与 material-ui 集成

带有 Next.js 和样式化组件的本地字体