Next.js 项目使用 styled-components 时样式失效的问题解决方法

在前端开发中,我们经常使用 styled-components 来管理项目的样式,而 Next.js 则是一个非常流行的 React 框架。然而,在使用这两个工具的时候,我们可能会遇到样式失效的问题。本文将介绍 Next.js 项目使用 styled-components 时样式失效的问题解决方法,并提供示例代码。

问题描述

在使用 Next.js 和 styled-components 的过程中,我们可能会遇到样式失效的问题。具体表现为,样式并没有应用到对应的组件上,或者只有部分样式生效。这个问题可能会出现在开发环境和生产环境中。

问题原因

造成这个问题的原因是 Next.js 的服务端渲染机制。在服务端渲染的过程中,styled-components 会生成一些样式标签,但是这些标签并没有被正确地注入到 HTML 中。因此,在客户端渲染的过程中,这些样式标签并没有被正确地加载,导致样式失效。

解决方法

为了解决这个问题,我们可以使用 styled-components 提供的 ServerStyleSheet 类来处理样式标签的注入。具体步骤如下:

  1. _document.js 文件中引入 ServerStyleSheet 类,并创建一个实例。
import Document, { Html, Head, Main, NextScript } 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();
    }
  }

  render() {
    return (
      <Html>
        <Head />
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}
  1. _app.js 文件中引入 styled-components 并使用 ThemeProvider 包裹应用。
import { ThemeProvider } from 'styled-components';
import GlobalStyle from '../styles/global';
import theme from '../styles/theme';

function MyApp({ Component, pageProps }) {
  return (
    <ThemeProvider theme={theme}>
      <GlobalStyle />
      <Component {...pageProps} />
    </ThemeProvider>
  );
}

export default MyApp;

这里的 GlobalStyletheme 分别是全局样式和主题配置,可以根据项目需要进行自定义。

  1. 在组件中使用 styled-components
import styled from 'styled-components';

const Title = styled.h1`
  font-size: 24px;
  color: ${({ theme }) => theme.colors.primary};
`;

function Home() {
  return <Title>Hello World!</Title>;
}

export default Home;

示例代码

下面是一个完整的 Next.js 项目,其中包含了使用 styled-components 的示例代码。

pages/_document.js

import Document, { Html, Head, Main, NextScript } 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();
    }
  }

  render() {
    return (
      <Html>
        <Head />
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}

pages/_app.js

import { ThemeProvider } from 'styled-components';
import GlobalStyle from '../styles/global';
import theme from '../styles/theme';

function MyApp({ Component, pageProps }) {
  return (
    <ThemeProvider theme={theme}>
      <GlobalStyle />
      <Component {...pageProps} />
    </ThemeProvider>
  );
}

export default MyApp;

pages/index.js

import styled from 'styled-components';

const Title = styled.h1`
  font-size: 24px;
  color: ${({ theme }) => theme.colors.primary};
`;

function Home() {
  return <Title>Hello World!</Title>;
}

export default Home;

styles/global.js

import { createGlobalStyle } from 'styled-components';

const GlobalStyle = createGlobalStyle`
  * {
    box-sizing: border-box;
  }

  body {
    margin: 0;
    padding: 0;
    font-family: sans-serif;
  }
`;

export default GlobalStyle;

styles/theme.js

const theme = {
  colors: {
    primary: '#0070f3',
  },
};

export default theme;

总结

在使用 Next.js 和 styled-components 的时候,我们可能会遇到样式失效的问题。这个问题的原因是 Next.js 的服务端渲染机制。为了解决这个问题,我们可以使用 styled-components 提供的 ServerStyleSheet 类来处理样式标签的注入。通过在 _document.js 文件中创建一个 ServerStyleSheet 实例,并在 _app.js 文件中使用 ThemeProvider 包裹应用,我们可以确保样式能够正确地注入到 HTML 中,从而解决样式失效的问题。

来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/658abfa6eb4cecbf2d004bbc


纠错
反馈