如何在样式组件之外获取主题?
Posted
技术标签:
【中文标题】如何在样式组件之外获取主题?【英文标题】:How to get the theme outside styled-components? 【发布时间】:2017-04-09 09:09:30 【问题描述】:我知道如何从使用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>
注意需要主题的属性怎么不叫
style
【问题讨论】:
【参考方案1】:从 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)
下面的原始回复(忽略这个!)
虽然没有官方解决方案,但我现在想出了:
创建一个高阶组件,负责获取当前主题并作为道具传递给组件:
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);
【讨论】:
我正在尝试在这样的功能组件上使用withTheme
:
export const circle = withTheme((theme) => (<circle fill=theme.circleColor r="40" />))
我收到一条错误消息,说它没有返回 React 节点,但是......所以我假设 withProps
目前不适用于功能组件?
呃。错字。 “所以我假设withProps
”应该是“所以我假设withTheme
”。抱歉这么多 cmets - 我不小心按了第一个,无法删除它,然后由于 5 分钟计时器而不允许编辑它......等等。
@aminimalanimal 它应该可以正常工作。您的组件是否在没有 withTheme 部分的情况下工作?如果是这样,请在此处打开一个问题:github.com/styled-components/styled-components/issues【参考方案2】:
你可以使用useTheme
钩子
import useTheme from 'styled-components';
const ExampleComponent = () =>
const theme = useTheme();
return (
<View>
<Card aCustomColorProperty=theme.color.sampleColor />
</View>
);
;
【讨论】:
【参考方案3】:创建 HOC 是处理主题的好方法。让我用 React 的 Context 分享另一个想法。
上下文允许您将数据从父节点传递给它的所有子节点。
每个孩子都可以通过在组件定义中定义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 只想要主题而不想要 i18n。他也可能是无国籍的:
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;
【讨论】:
上下文很棒,但我遇到了问题。沿树向下的组件没有收到新的上下文值,因为上下文不保证传播:如果一个组件不更新,它的所有子组件也不会更新。 我刚刚发现这篇文章解释了 Context 的问题并提供了解决方案:medium.com/@mweststrate/… 事实证明,这个解决方案是 styled-components 在内部所做的,在我的回答中,我订阅了 styled -组件上下文。看起来不错。你怎么看? @BrunoLemos 从我的角度来看,您的解决方案对我来说看起来不错!我们可能会将类似的内容添加到核心或直接公开 CHANNEL 并为此添加文档,您介意提交代码问题吗?谢谢!【参考方案4】:要在功能组件中使用withTheme
,请创建一个高阶组件。
高阶组件: 高阶组件,或 HOCs,是在以某种方式增强组件后获取组件并输出新组件的函数:
const EnhancedHOCComponent = hoc(OriginalReactComponent)
功能组件中的主题示例
const MyButton = (theme) =>
const red = theme.colors.red;
return (<div style= color: red >how are you</div>)
`
const Button = withTheme(MyButton);
export default Button;
【讨论】:
以上是关于如何在样式组件之外获取主题?的主要内容,如果未能解决你的问题,请参考以下文章