codecamp

styled-components 服务端渲染

服务端渲染

styled-components 通过样式注水(with stylesheet rehydration)支持并发服务端渲染. 其核心思想是,每当在服务器上渲染应用时, 为 React 树创建一个ServerStyleSheet 和一个 provider ,通过 context API 来接收样式.

这不会影响全局样式,例如 keyframes 或者 createGlobalStyle ,并且允 styled-components 与 React DOM 的 SSR API 共同使用.

设置

为了可靠的执行 SSR,正确的生成客户端 bundle,请使用 babel plugin. 它通过为每个 styled component 添加确定的 ID 来防止校验错误. 更多信息请参考 tooling documentation .

对于 TypeScript 用户, TS 大师 Igor Oleinikov 整合了webpack ts-loader / awesome-typescript-loader 工具链 TypeScript plugin 来完成类似的任务.

If possible, we definitely recommend using the babel plugin though because it is updated the most frequently. It's now possible to compile TypeScript using Babel, so it may be worth switching off TS loader and onto a pure Babel implementation to reap the ecosystem benefits.

示例

基本 API 的使用如下:

import { renderToString } from 'react-dom/server'
import { ServerStyleSheet } from 'styled-components'

const sheet = new ServerStyleSheet()
const html = renderToString(sheet.collectStyles(<YourApp />))
const styleTags = sheet.getStyleTags() // or sheet.getStyleElement();

collectStyles 方法将元素包装进了 provider.也可以选择直接使用 StyleSheetManager provider.确保不要再客户端使用即可.

import { renderToString } from 'react-dom/server'
import { ServerStyleSheet, StyleSheetManager } from 'styled-components'

const sheet = new ServerStyleSheet()
const html = renderToString(
  <StyleSheetManager sheet={sheet.instance}>
    <YourApp />
  </StyleSheetManager>
)

const styleTags = sheet.getStyleTags() // or sheet.getStyleElement();

sheet.getStyleTags() 方法返回多个字符串的 <style> 标签. 当向 HTML 输出增加 CSS 时需要考虑这一点.

作为另一种选择, ServerStyleSheet 实例也提供 getStyleElement() 方法,返回一个 React 元素的数组.

注意sheet.getStyleTags() 和sheet.getStyleElement() 只能在元素渲染和调用. 所以sheet.getStyleElement()中的组件不能与 合并为一个更大的组件.

Next.js

首先添加一个自定义的 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()
    }
  }
}

将服务端你渲染的样式注入 <head>.


Streaming Rendering

styled-components 提供一个与ReactDOMServer.renderToNodeStream()搭配使用的流式 API . 一个流式实现需要以下两部分:

在服务器上:

ReactDOMServer.renderToNodeStream 发出一个 styled-components 包装过的"可读"流. 当整个 HTML 块被推到流上时,如果任何相应的样式已经可以渲染,一个样式块会被附加到 React HTML 并发送给客户端浏览器.

import { renderToNodeStream } from 'react-dom/server'
import styled, { ServerStyleSheet } from 'styled-components'

// if you're using express.js, you'd have access to the response object "res"

// typically you'd want to write some preliminary HTML, since React doesn't handle this
res.write('<html><head><title>Test</title></head><body>')

const Heading = styled.h1`
  color: red;
`

const sheet = new ServerStyleSheet()
const jsx = sheet.collectStyles(<Heading>Hello SSR!</Heading>)
const stream = sheet.interleaveWithNodeStream(renderToNodeStream(jsx))

// you'd then pipe the stream into the response object until it's done
stream.pipe(
  res,
  { end: false }
)

// and finalize the response with closing HTML
stream.on('end', () => res.end('</body></html>'))

在客户端里:

import { hydrate } from 'react-dom'

hydrate()
// your client-side react implementation

当客户端注水完毕后, styled-components 将接管重新定位后的流式样式并且注入动态样式.


styled-components 媒体模板
styled-components 参考其他部件
温馨提示
下载编程狮App,免费阅读超1000+编程语言教程
取消
确定
目录

关闭

MIP.setData({ 'pageTheme' : getCookie('pageTheme') || {'day':true, 'night':false}, 'pageFontSize' : getCookie('pageFontSize') || 20 }); MIP.watch('pageTheme', function(newValue){ setCookie('pageTheme', JSON.stringify(newValue)) }); MIP.watch('pageFontSize', function(newValue){ setCookie('pageFontSize', newValue) }); function setCookie(name, value){ var days = 1; var exp = new Date(); exp.setTime(exp.getTime() + days*24*60*60*1000); document.cookie = name + '=' + value + ';expires=' + exp.toUTCString(); } function getCookie(name){ var reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)'); return document.cookie.match(reg) ? JSON.parse(document.cookie.match(reg)[2]) : null; }