如何在 styled-components 之外获取主题?

How to get the theme outside styled-components?

我知道如何从使用 styled 方式创建的组件中获取 theme

const StyledView = styled.View`
    color: ${({ theme }) => theme.color};
`;

但是如何从普通组件获取或将其应用于不同的属性?示例:

index.js

<ThemeProvider theme={{ color: 'red' }}>
    <Main />
</ThemeProvider>

main.js

<View>
    <Card aCustomColorProperty={GET COLOR FROM THEME HERE} />
</View>

Notice how the property that needs the theme is not called style

从 v5.0 开始,您可以使用 useTheme 挂钩:

import React, { useTheme } from 'styled-components';

export function MyComponent() {
  const theme = useTheme();

  return <p style={{ color: theme.color }}>Text</p>;
}

你也可以使用我很久以前从v1.2开始贡献的withTheme高阶组件:

import { withTheme } from 'styled-components'

class MyComponent extends React.Component {
  render() {
    const { theme } = this.props

    console.log('Current theme: ', theme);
    // ...
  }
}

export default withTheme(MyComponent)



original response below (ignore this!)

虽然没有正式的解决方案,但我现在想出了:

创建一个高阶组件,负责获取当前主题并作为 prop 传递给组件:

import React from 'react';
import { CHANNEL } from 'styled-components/lib/models/ThemeProvider';

export default Component => class extends React.Component {
  static contextTypes = {
    [CHANNEL]: React.PropTypes.func,
  };

  state = {
    theme: undefined,
  };

  componentWillMount() {
    const subscribe = this.context[CHANNEL];
    this.unsubscribe = subscribe(theme => {
      this.setState({ theme })
    });
  }

  componentWillUnmount() {
    if (typeof this.unsubscribe === 'function') this.unsubscribe();
  }

  render() {
    const { theme } = this.state;

    return <Component theme={theme} {...this.props} />
  }
}

然后,在你需要访问的组件上调用它 theme:

import Themable from './Themable.js'
  
const Component = ({ theme }) => <Card color={theme.color} />

export default Themable(Component);

创建 HOC 是解决主题化的好方法。让我使用 React 的 Context.

分享另一个想法

Context 允许您将数据从 parent 节点传递给它的所有 children。 每个 child 可以选择通过在组件定义中定义 contextTypes 来访问 context

假设 App.js 是您的根。

import themingConfig from 'config/themes';
import i18nConfig from 'config/themes';
import ChildComponent from './ChildComponent';
import AnotherChild from './AnotherChild';

class App extends React.Component {
    getChildContext() {
        return {
            theme: themingConfig,
            i18n: i18nConfig, // I am just showing another common use case of context
        }
    }

    render() {
          return (
              <View>
                  <ChildComponent />
                  <AnotherChild myText="hola world" />
              </View>
          );
    }
}

App.childContextTypes = {
    theme: React.PropTypes.object,
    i18n: React.PropTypes.object
};

export default App;

现在我们的 `ChildComponent.js 谁想要一些主题和 i18n 字符串

class ChildComponent extends React.Component {
    render() {
        const { i18n, theme } = this.context;

        return (
           <View style={theme.textBox}>
               <Text style={theme.baseText}>
                   {i18n.someText}
               </Text>
           </View>
        );
    }
}

ChildComponent.contextTypes = {
    theme: React.PropTypes.object,
    i18n: React.PropTypes.object
};

export default ChildComponent;

AnotherChild.js 只想要主题不想要国际化的人。他也可能是无国籍人:

const AnotherChild = (props, context) {
    const { theme } = this.context;
    return (<Text style={theme.baseText}>{props.myText}</Text>);
}

AnotherChild.propTypes = {
    myText: React.PropTypes.string
};

AnotherChild.contextTypes = {
    theme: React.PropTypes.object
};

export default AnotherChild;

要在功能组件中使用 withTheme,请创建 Higher-order-component。

Higher-order-component: higher-order components, or HOCs, are functions that take a component and output a new component after enhancing it in some manner:
const EnhancedHOCComponent = hoc(OriginalReactComponent)

功能组件中的 withTheme 示例


const MyButton = ({theme}) => {
const red = theme.colors.red;

return (<div  style={{ color: red}} >how are you</div>)
}`

const Button =  withTheme(MyButton);
export default Button;

你可以使用useTheme挂钩

import { useTheme } from 'styled-components';

const ExampleComponent = () => {
  const theme = useTheme();

  return (
    <View>
       <Card aCustomColorProperty={theme.color.sampleColor} />
    </View>
  );
};