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 在這裡很方便,這樣您就可以確保每次使用它們時都已註冊主題和介面。您也可以將其設定為初始化程式,並將其新增到您的 bundle 頂部,然後直接在您的組件中使用 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')

同樣地,也可以透過設定 themePropName 選項來自訂主題 prop 的名稱。

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);

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

範例

使用 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 /> 會將從 css(..styles) 產生的 className 向下傳遞到最後的葉節點。

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 的組織和專案.