在服务器上渲染需要样式的 React 组件

Posted

技术标签:

【中文标题】在服务器上渲染需要样式的 React 组件【英文标题】:Render React components which require styles on server 【发布时间】:2015-05-30 17:01:51 【问题描述】:

我有需要内部样式的 React.js 组件:

import './styles.css
import React from 'react';

export default class Basket extends React.Component 
    ...

现在我想让我的应用同构并在服务器上预渲染它..

Babel 开始抱怨 css 文件也就不足为奇了:

SyntaxError: /Users/dmitri/github/app/src/client/pages/styles.css: Unexpected token (3:5)
  2 |
> 3 | body 
    |      ^
  4 |     background-color: #ddd;
  5 | 
  6 |

如何让它发挥作用? node-jsx-https://github.com/petehunt/node-jsx/issues/29也有类似的讨论

我应该为此导入添加if (browser) 语句吗?

【问题讨论】:

使用 systemjs 服务器端可能有效:github.com/systemjs/systemjs 如果您从源代码中预处理包含.css 的导入会怎样? recast 可以做到这一点。稍后可能会为相同的任务实现一个 Babel 插件。目前还没有稳定的 API,所以我还不能推荐。 【参考方案1】:

这是一种不同的方法,但请查看Radium。您可以将样式声明为 JS 对象,这样服务器就不必知道或关心 CSS 是什么。

Radium 页面的示例:

var React = require('react');
var Radium = require('radium');
var color = require('color');

var Button = React.createClass(Radium.wrap(
  displayName: "Button",

  propTypes: 
    kind: React.PropTypes.oneOf(['primary', 'warning']).isRequired
  ,

  render: function () 
    // Radium extends the style attribute to accept an array. It will merge
    // the styles in order. We use this feature here to apply the primary
    // or warning styles depending on the value of the `kind` prop. Since its
    // all just javascript, you can use whatever logic you want to decide which
    // styles are applied (props, state, context, etc).
    return (
      <button
        style=[
          styles.base,
          styles[this.props.kind]
        ]>
        this.props.children
      </button>
    );
  
));

// You can create your style objects dynamically or share them for
// every instance of the component.
var styles = 
  base: 
    padding: '1.5em 2em',
    border: 0,
    borderRadius: 4,
    color: '#fff',
    cursor: 'pointer',
    fontSize: 16,
    fontWeight: 700,

    // Adding interactive state couldn't be easier! Add a special key to your
    // style object (:hover, :focus, :active, or @media) with the additional rules.
    ':hover': 
      background: color('#0074d9').lighten(0.2).hexString()
    ,

    // If you specify more than one, later ones will override earlier ones.
    ':focus': 
      boxShadow: '0 0 0 3px #eee, 0 0 0 6px #0074D9',
      outline: 'none'
    ,
  ,

  primary: 
    background: '#0074D9'
  ,

  warning: 
    background: '#FF4136'
  
;

请记住,如果您不喜欢内联 css,您可以随时在单独的 JS 中定义您的样式并导入它们。

【讨论】:

【参考方案2】:

我的需求和你完全一样。我使用 webpack 来打包我的应用程序。在 webpack 中,你可以像这样定义多个变量:

var define = new webpack.DefinePlugin(
    "process.env": 
        BROWSER: JSON.stringify(true)
    
);

在我的 jsx 文件中:

if (process.env.BROWSER) 
    require('my-css');

我认为,还有其他方法可以管理 css。这是一种方法。

【讨论】:

以上是关于在服务器上渲染需要样式的 React 组件的主要内容,如果未能解决你的问题,请参考以下文章

来自不同组件的 React + Material-UI 样式类在静态服务时发生冲突

如何在 react.js 的父组件中检测子渲染

React-testing-library 不从样式表渲染计算样式

在React中,如何检测我的组件是从客户端还是服务器呈现?

React 服务端渲染与预渲染

如何加载新版本react addon