Next.js 9+ FOUC(Flash 或无样式内容)与样式组件
Next.js 9+ FOUC (Flash or Unstyled Content) with Styled Components
在这个问题上花了几天时间从大多数 SA 和 Reddit 上寻找解决方案和想法,但无济于事..
在生产和本地加载时,每个加载都呈现整个 html,在注入 DOM..
之前没有任何样式
目前这是我的项目关键文件:
_document.js
import { ServerStyleSheet } from "styled-components";
import Document, { Main, NextScript } from "next/document";
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 lang="en">
<Head>
<title>namesjames</title>
<link rel="icon" href="/favicon.ico" />
<script src="/static/chrome-fix.js" />
<link href="/above-the-fold.css" />
</Head>
<body>
<script src="/noflash.js" />
<Main />
<NextScript />
<script> </script>
</body>
</html>
);
}
}
_app.js
/* eslint-disable class-methods-use-this */
import App from "next/app";
import React from "react";
import { ThemeProvider } from "styled-components";
import { ParallaxProvider } from 'react-scroll-parallax';
import Header from "../components/Header";
import theme from "../theme";
import GlobalStyles from "../GlobalStyles";
import DarkModeToggle from '../components/toggle/toggleMode';
import Footer from '../components/Footer'
import LazyLoad from 'react-lazy-load';
import Router from 'next/router';
import styled from 'styled-components'
// import '../style.css'
const Loaded = styled.div`
opacity: ${(props) => props.loaded ? "1" : "0"};
`
export default class MyApp extends App {
state = { isLoading: false, loaded: false }
componentDidMount() {
// Logging to prove _app.js only mounts once,
// but initializing router events here will also accomplishes
// goal of setting state on route change
console.log('MOUNT');
this.setState({loaded: true})
Router.events.on('routeChangeStart', () => {
this.setState({ isLoading: true });
console.log('loading is true, routechangeStart')
});
Router.events.on('routeChangeComplete', () => {
this.setState({ isLoading: false });
console.log('loading is false, routeChangeComplete')
});
Router.events.on('routeChangeError', () => {
this.setState({ isLoading: false });
console.log('loading is false, routeChangeError')
});
}
render(): JSX.Element {
const { isLoading } = this.state;
const { Component, pageProps, router, loaded } = this.props;
return (
<Loaded loaded={this.state.loaded}>
<ThemeProvider theme={theme}>
<GlobalStyles />
<ParallaxProvider>
<Header />
{isLoading && 'STRING OR LOADING COMPONENT HERE...'}
<Component {...pageProps} key={router.route} />
<LazyLoad offsetVertical={500}>
<Footer />
</LazyLoad>
</ParallaxProvider>
<DarkModeToggle />
</ThemeProvider>
</Loaded>
);
}
}
index.js
import { color } from "styled-system";
import { OffWhite } from "../util/tokens";
import Hero from "../components/Hero";
import Banner from '../components/Banner'
import TitleText from '../components/TitleText'
import HomeTitleCopyScene from '../components/HomeTitleCopyScene'
import TwoCards from '../components/TwoCards'
import LazyLoad from 'react-lazy-load';
function Home(): JSX.Element {
return (
<div className="container">
<Banner />
<HomeTitleCopyScene />
<LazyLoad offsetVertical={1000}>
<TwoCards />
</LazyLoad>
</div>
);
}
export default Home;
正如某些人可能看到的那样,我已经尝试了多种实现,但对于现阶段的实现方式有点困惑..
感谢任何帮助,我可以根据要求提供更多信息。非常感谢
我找到了两个有用的解决方案 -->
- 是硬样式 opacity:0 到 JSX,然后在样式注入到 DOM 应用不透明度:1 !important 到显示的任何组件上..
<section className="cards-block" style={{opacity:0}}>
- 虽然今天早上这很有效,但我在开发过程中的某个时候发现我错误地从
next/head
导入了 Head
并在我的 _document.js
中使用了它,而不是使用正确的 Head
来自 next/documents
..
// import Head from "next/head"; --> incorrect
import { ServerStyleSheet } from "styled-components";
import Document, { Head, Main, NextScript } from "next/document";
Ergo -> 没有 FOUC 的正确渲染和注入元素
希望这对外面的人有帮助
我为我的小型投资组合项目找到了解决方法:
刚刚将此内联 css 包含到我的自定义 <head>
中 _document.js
:
{<style dangerouslySetInnerHTML={{__html: `
html {background: #333}
body #__next div {visibility: hidden}
body.loaded #__next div {visibility: visible}
`}}></style>}
“已加载”class 已添加到 _app.js
中的正文:
if (process.browser) {
document.body.classList.add("loaded")
}
我很确定这是否是一个好的解决方案,任何建议将不胜感激:)
在这个问题上花了几天时间从大多数 SA 和 Reddit 上寻找解决方案和想法,但无济于事..
在生产和本地加载时,每个加载都呈现整个 html,在注入 DOM..
之前没有任何样式目前这是我的项目关键文件:
_document.js
import { ServerStyleSheet } from "styled-components";
import Document, { Main, NextScript } from "next/document";
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 lang="en">
<Head>
<title>namesjames</title>
<link rel="icon" href="/favicon.ico" />
<script src="/static/chrome-fix.js" />
<link href="/above-the-fold.css" />
</Head>
<body>
<script src="/noflash.js" />
<Main />
<NextScript />
<script> </script>
</body>
</html>
);
}
}
_app.js
/* eslint-disable class-methods-use-this */
import App from "next/app";
import React from "react";
import { ThemeProvider } from "styled-components";
import { ParallaxProvider } from 'react-scroll-parallax';
import Header from "../components/Header";
import theme from "../theme";
import GlobalStyles from "../GlobalStyles";
import DarkModeToggle from '../components/toggle/toggleMode';
import Footer from '../components/Footer'
import LazyLoad from 'react-lazy-load';
import Router from 'next/router';
import styled from 'styled-components'
// import '../style.css'
const Loaded = styled.div`
opacity: ${(props) => props.loaded ? "1" : "0"};
`
export default class MyApp extends App {
state = { isLoading: false, loaded: false }
componentDidMount() {
// Logging to prove _app.js only mounts once,
// but initializing router events here will also accomplishes
// goal of setting state on route change
console.log('MOUNT');
this.setState({loaded: true})
Router.events.on('routeChangeStart', () => {
this.setState({ isLoading: true });
console.log('loading is true, routechangeStart')
});
Router.events.on('routeChangeComplete', () => {
this.setState({ isLoading: false });
console.log('loading is false, routeChangeComplete')
});
Router.events.on('routeChangeError', () => {
this.setState({ isLoading: false });
console.log('loading is false, routeChangeError')
});
}
render(): JSX.Element {
const { isLoading } = this.state;
const { Component, pageProps, router, loaded } = this.props;
return (
<Loaded loaded={this.state.loaded}>
<ThemeProvider theme={theme}>
<GlobalStyles />
<ParallaxProvider>
<Header />
{isLoading && 'STRING OR LOADING COMPONENT HERE...'}
<Component {...pageProps} key={router.route} />
<LazyLoad offsetVertical={500}>
<Footer />
</LazyLoad>
</ParallaxProvider>
<DarkModeToggle />
</ThemeProvider>
</Loaded>
);
}
}
index.js
import { color } from "styled-system";
import { OffWhite } from "../util/tokens";
import Hero from "../components/Hero";
import Banner from '../components/Banner'
import TitleText from '../components/TitleText'
import HomeTitleCopyScene from '../components/HomeTitleCopyScene'
import TwoCards from '../components/TwoCards'
import LazyLoad from 'react-lazy-load';
function Home(): JSX.Element {
return (
<div className="container">
<Banner />
<HomeTitleCopyScene />
<LazyLoad offsetVertical={1000}>
<TwoCards />
</LazyLoad>
</div>
);
}
export default Home;
正如某些人可能看到的那样,我已经尝试了多种实现,但对于现阶段的实现方式有点困惑..
感谢任何帮助,我可以根据要求提供更多信息。非常感谢
我找到了两个有用的解决方案 -->
- 是硬样式 opacity:0 到 JSX,然后在样式注入到 DOM 应用不透明度:1 !important 到显示的任何组件上..
<section className="cards-block" style={{opacity:0}}>
- 虽然今天早上这很有效,但我在开发过程中的某个时候发现我错误地从
next/head
导入了Head
并在我的_document.js
中使用了它,而不是使用正确的Head
来自next/documents
..
// import Head from "next/head"; --> incorrect
import { ServerStyleSheet } from "styled-components";
import Document, { Head, Main, NextScript } from "next/document";
Ergo -> 没有 FOUC 的正确渲染和注入元素
希望这对外面的人有帮助
我为我的小型投资组合项目找到了解决方法:
刚刚将此内联 css 包含到我的自定义 <head>
中 _document.js
:
{<style dangerouslySetInnerHTML={{__html: `
html {background: #333}
body #__next div {visibility: hidden}
body.loaded #__next div {visibility: visible}
`}}></style>}
“已加载”class 已添加到 _app.js
中的正文:
if (process.browser) {
document.body.classList.add("loaded")
}
我很确定这是否是一个好的解决方案,任何建议将不胜感激:)