使用主题

Emotion的主题功能是在@emotion/react库中提供的,跟React的Context一样,主题功能也是需要使用<ThemeProvider>在全局提供目前要使用的主题,然后在组件树的枝叶部分就可以使用propswithTheme()或者useTheme()来使用主题,并在主题发生变化的时候使组件发生重新渲染。

<ThemeProvider>使用theme属性接受一个对象来作为主题。这个用于定义主题的对象,其中都是由样式属性组成,这些样式属性的值将构成所有组件中对应样式属性的默认值。一个应用中<ThemeProvider>可以使用多个,而且不同主题之间定义的相同样式属性之间会根据<ThemeProvider>之间的层级关系产生覆盖。

Tip

在定义主题的对象中使用样式属性可以比较明确的说明属性值定义的目的,但是Emotion对采用什么样的对象属性没有限制,一个普通的对象也可以作为主题对象使用。

例如以下示例。

import { ThemeProvider } from '@emotion/react';

const theme = {
  backgroundColor: 'gray',
  color: 'red'
};

const adjustTheme = ancestorTheme => ({ ...ancestorTheme, color: 'blue' });

function Container() {
  return (
    <ThemeProvider theme={theme}>
      <ThemeProvider theme={adjustTheme}>
        <p>Some text.</p>
      </ThemeProvider>
    </ThemeProvider>
  );
}

在组件中应用主题可以通过两个途径,一个是使用withTheme函数定义高阶组件,一个是使用useTheme Hook。withTheme可以将主题的配置注入到组件的this.props.theme中。例如以下示例。

import React from 'react';
import { jsx, ithTheme } from '@emotion/react';

class Container extends React.Component {
  render() {
    return (
      <div
        css={{
          color: this.props.theme.color
        }}>
        Some text.
      </div>
    );
  }
}

const ContainerWithTheme = withTheme(Container);

在使用React新的Hook语法的时候,useTheme就可以用来把主题设置引入组件。例如可以把上面这个示例改成以下样子。

import { jsx, ThemeProvider, useTheme } from '@emotion/react';

const theme = {
  colors: {
    primary: 'red'
  }
};

function TextWithTheme(props) {
  const theme = useTheme();
  return <div css={{ color: theme.colors.primary }}>Some text.</div>;
}

function App() {
  return (
    <ThemeProvider theme={theme}>
      <TextWithTheme />
    </ThemeProvider>
  );
}