react-with-styles

在React中使用CSS-in-JavaScript和主题,无需紧密耦合到一种实现方式
1,659
作者Joe Lencioni

在你的React组件中使用CSS-in-JavaScript,无需紧密耦合到一种实现方式(例如 AphroditeRadiumReact Native)。在定义样式时轻松访问共享主题信息(例如颜色、字体)。

接口

其他资源

使用方法

创建一个模块,导出一个包含共享主题信息(如颜色)的对象。

export default {
  color: {
    primary: '#FF5A5F',
    secondary: '#00A699',
  },
};

注册你的主题和接口。例如,如果你的主题由MyTheme.js导出,并且你想要使用Aphrodite,你可以在你自己的withStyles.js文件中进行设置。

import ThemedStyleSheet from 'react-with-styles/lib/ThemedStyleSheet';
import aphroditeInterface from 'react-with-styles-interface-aphrodite';
import { css, withStyles } from 'react-with-styles';

import MyTheme from './MyTheme';

ThemedStyleSheet.registerTheme(MyTheme);
ThemedStyleSheet.registerInterface(aphroditeInterface);

export { css, withStyles, ThemedStyleSheet };

在这里传递react-with-styles中的csswithStyles很方便,这样你无论在哪里使用它们,都能确保主题和接口已被注册。你也可以将其设置为添加到捆绑包顶部的初始化程序,然后直接在组件中使用react-with-styles

在你的组件中,从上面的withStyles.js文件中,使用withStyles()定义样式,使用css()使用它们。

import React from 'react';
import PropTypes from 'prop-types';
import { css, withStyles } from './withStyles';

function MyComponent({ styles }) {
  return (
    <div>
      <a
        href="/somewhere"
        {...css(styles.firstLink)}
      >
        A link to somewhere
      </a>

      {' '}
      and
      {' '}

      <a
        href="/somewhere-else"
        {...css(styles.secondLink)}
      >
        a link to somewhere else
      </a>
    </div>
  );
}

MyComponent.propTypes = {
  styles: PropTypes.object.isRequired,
};

export default withStyles(({ color }) => ({
  firstLink: {
    color: color.primary,
  },

  secondLink: {
    color: color.secondary,
  },
}))(MyComponent);

ThemedStyleSheet

注册主题和接口。

ThemedStyleSheet.registerTheme(theme)

注册主题。theme是一个对象,包含你希望在为组件设置样式时可用的属性。

import ThemedStyleSheet from 'react-with-styles/lib/ThemedStyleSheet';

ThemedStyleSheet.registerTheme({
  color: {
    primary: '#FF5A5F',
    secondary: '#00A699',
  },
});

ThemedStyleSheet.registerInterface(interface)

指示react-with-styles如何处理你的样式。

import ThemedStyleSheet from 'react-with-styles/lib/ThemedStyleSheet';
import aphroditeInterface from 'react-with-styles-interface-aphrodite';

ThemedStyleSheet.registerInterface(aphroditeInterface);

withStyles([ stylesThunk [, options ] ])

这是一个高阶函数,它返回一个用于包装React组件以使用主题添加样式的高阶组件。我们使用它来使主题样式更容易使用。

stylesThunk将接收主题作为参数,它应该返回一个包含组件样式的对象。

被包装的组件将接收一个包含此组件的已处理样式的styles prop和一个包含主题对象的theme prop。大多数情况下,你只需要styles prop。对theme prop的依赖应该最小化。

使用示例

import React from 'react';
import { css, withStyles } from './withStyles';

function MyComponent({ styles }) {
  return (
    <div {...css(styles.container)}>
      Try to be a rainbow in someone's cloud.
    </div>
  );
}

export default withStyles(({ color, unit }) => ({
  container: {
    color: color.primary,
    marginBottom: 2 * unit,
  },
}))(MyComponent);

或者,作为装饰器

import React from 'react';
import { css, withStyles } from './withStyles';

@withStyles(({ color, unit }) => ({
  container: {
    color: color.primary,
    marginBottom: 2 * unit,
  },
}))
export default function MyComponent({ styles }) {
  return (
    <div {...css(styles.container)}>
      Try to be a rainbow in someone's cloud.
    </div>
  );
}

选项

pureComponent(默认值:false,React 15.3.0+)

默认情况下,withStyles()将创建一个扩展React.Component的组件。如果你想应用React.PureComponent提供的shouldComponentUpdate()优化,可以将pureComponent选项设置为true。请注意,React.PureComponent是在React 15.3.0中引入的,因此只有在你使用该版本或更高版本时,此方法才有效。

stylesPropName(默认值:'styles'

默认情况下,withStyles()styles prop中的样式传递给被包装的组件,但是可以通过设置stylesPropName选项来自定义此prop的名称。如果你已经有一个名为styles的prop并且无法更改它,这将很有用。

import React from 'react';
import { css, withStyles } from './withStyles';

function MyComponent({ withStylesStyles }) {
  return (
    <div {...css(withStylesStyles.container)}>
      Try to be a rainbow in someone's cloud.
    </div>
  );
}

export default withStyles(({ color, unit }) => ({
  container: {
    color: color.primary,
    marginBottom: 2 * unit,
  },
}), { stylesPropName: 'withStylesStyles' })(MyComponent);

themePropName(默认值 'theme'

同样,主题prop名称也可以通过设置themePropName选项来自定义。

import React from 'react';
import { css, withStyles } from './withStyles';

function MyComponent({ styles, withStylesTheme }) {
  return (
    <div {...css(styles.container)}>
      <Background color={withStylesTheme.color.primary}>
        Try to be a rainbow in someone's cloud.
      </Background>
    </div>
  );
}

export default withStyles(({ color, unit }) => ({
  container: {
    color: color.primary,
    marginBottom: 2 * unit,
  },
}), { themePropName: 'withStylesTheme' })(MyComponent);

flushBefore(默认值:false

某些组件依赖于挂载时组件树中之前的样式已准备好(例如尺寸计算)。一些接口异步地将样式添加到页面,这对这是个障碍。因此,我们提供了一个在渲染周期开始之前刷新缓冲样式的选项。接口需要定义这意味着什么。

css(...styles)

此函数接受由withStyles()处理的样式、普通对象或这些内容的数组。它返回一个具有不透明结构的对象,必须将其展开到JSX元素中。

import React from 'react';
import { css, withStyles } from './withStyles';

function MyComponent({ bold, padding, styles }) {
  return (
    <div {...css(styles.container, { padding })}>
      Try to be a rainbow in{' '}
      <a
        href="/somewhere"
        {...css(styles.link, bold && styles.link_bold)}
      >
        someone's cloud
      </a>
    </div>
  );
}

export default withStyles(({ color, unit }) => ({
  container: {
    color: color.primary,
    marginBottom: 2 * unit,
  },

  link: {
    color: color.secondary,
  },

  link_bold: {
    fontWeight: 700,
  },
}))(MyComponent);

classNamestyle prop不能与css()在相同的元素上使用。

示例

使用React Router的Link

React Router<Link/><IndexLink/>组件接受activeClassName='...'activeStyle={{...}}作为prop。如前所述,css(...styles)必须展开到JSX,因此直接传递styles.thing甚至css(styles.thing)将不起作用。为了模拟activeClassName/activeStyles,你可以使用React Router的withRouter()高阶组件将router作为prop传递给你的组件,并根据router.isActive(pathOrLoc, indexOnly)切换样式。这是有效的,因为<Link />将生成的classNamecss(..styles)传递到最终的叶子。

import React from 'react';
import { withRouter, Link } from 'react-router';
import { css, withStyles } from '../withStyles';

function Nav({ router, styles }) {
  return (
    <div {...css(styles.container)}>
      <Link
        to="/"
        {...css(styles.link, router.isActive('/', true) && styles.link_bold)}
      >
        home
      </Link>
      <Link
        to="/somewhere"
        {...css(styles.link, router.isActive('/somewhere', true) && styles.link_bold)}
      >
        somewhere
      </Link>
    </div>
  );
}

export default withRouter(withStyles(({ color, unit }) => ({
  container: {
    color: color.primary,
    marginBottom: 2 * unit,
  },

  link: {
    color: color.primary,
  },

  link_bold: {
    fontWeight: 700,
  }
}))(Nav));

实际应用

使用react-with-styles的组织和项目.