Next.js App路由 Styled-componets 首屏和刷新出现样式闪动 解决方法

424 阅读1分钟

Next.js App路由 Styled-componets 首屏和刷新出现样式闪动

配置next.config.js

/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
  
  compiler: {
    styledComponents: true, // 添加
  },
};

module.exports = nextConfig;

修改注册样式的代码

'use client'

import React, { useState } from 'react'
import { useServerInsertedHTML } from 'next/navigation'
import { ServerStyleSheet, StyleSheetManager } from 'styled-components'

export default function StyledComponentsRegistry({
    children,
}: {
    children: React.ReactNode
}) {
    // Only create stylesheet once with lazy initial state
    // x-ref: https://reactjs.org/docs/hooks-reference.html#lazy-initial-state
    const [styledComponentsStyleSheet] = useState(() => new ServerStyleSheet())

    useServerInsertedHTML(() => {
        const styles = styledComponentsStyleSheet.getStyleElement()
        styledComponentsStyleSheet.instance.clearTag()
        return styles
    })

    if (typeof window !== 'undefined') return <>{children}</>

    return (
        <StyleSheetManager sheet={styledComponentsStyleSheet.instance}>
            {children}
        </StyleSheetManager>
    )
}

StyledComponentsRegistry组件,用于处理在服务器端渲染(Server Side Rendering)中使用styled-components库的样式注册。

该组件接收一个children参数,表示需要渲染的子组件。

在组件内部,使用了React的useState钩子来创建一个styledComponentsStyleSheet的状态变量,其初始值是通过new ServerStyleSheet()创建的ServerStyleSheet实例。

接着,使用useServerInsertedHTML自定义钩子,用于获取在服务器端渲染期间插入的HTML。在钩子回调函数中,首先通过styledComponentsStyleSheet.getStyleElement()获取到样式表元素,然后调用styledComponentsStyleSheet.instance.clearTag()方法来移除样式标签。最后,将获取到的样式表元素返回。

接着,通过判断typeof window !== 'undefined'来确定当前代码执行的环境是服务器端还是客户端。如果是客户端,则直接将children返回。

如果是服务器端,则使用StyleSheetManager组件将styledComponentsStyleSheet.instance作为sheet属性传入,以在子组件中共享样式表。

最后,将children作为子元素渲染在StyleSheetManager组件中。

总之,该组件主要用于在服务器端渲染中处理styled-components的样式注册,并确保在客户端和服务器端的渲染结果一致。