我希望能够为我的所有组件设置一个全局主题(变量集)来继承和扩展它们的默认变量。例如,我有一个button
组件,其默认样式(内联CSS)引用了一组变量,例如primaryColor
,...我希望能够更新这些变量很容易在我使用这些组件的任何地方,而无需将它们明确地传递给组件。
例如,我喜欢以下行为,我可以(1)将它们包装在一个组件中并让primaryColor
级联到每个Button
组件或(2)导出这个更高阶组件中的组件和feed更新道具等...但是,我无法使这些方法工作。也许,有更好的方法或......
(1)
render() {
return (
<Theme variables={{ 'primaryColor': 'red' }}>
<Button />
<SecondButton />
<ThirdButton />
</Theme>
);
}
(2)
render() {
return (
<div>
<Button />
<SecondButton />
<ThirdButton />
</div>
);
}
export default Theme(SampleComponent)
显然,这种方法可以正常传递给每个组件:
render() {
return (
<div>
<Button variables={{ 'primaryColor': 'red' }} />
<SecondButton variables={{ 'primaryColor': 'red' }} />
<ThirdButton variables={{ 'primaryColor': 'red' }} />
</div>
);
}
答案 0 :(得分:5)
我可以看到一些方法可以实现这一目标:
有限,但允许通过&#39;额外&#39;用于指导组件子项的道具:
import React, { Component, Children } from 'react';
class Theme extends Component {
getChildren () {
const { children, variables } = this.props;
// Clone the child components and extend their props
return Children.map(children, (child) => React.cloneElement(child, {
variables
}));
}
render () {
return Children.only(this.getChildren());
}
}
// Example
<Theme variables={{ 'primaryColor': 'red' }}>
<Button />
<SecondButton />
<ThirdButton />
</Theme>
将变量传递到React树的任何部分的最简单方法是使用React documentation中描述的上下文(这个确切的用例也是如此):
// Context provider
class ThemeProvider extends Component {
getChildContext() {
return {
theme: this.props.variables
};
}
render() {
return Children.only(this.props.children);
}
}
ThemeProvider.childContextTypes = {
theme: PropTypes.object.isRequired
};
// HOC
function Theme(WrappedComponent) {
class ThemeWrapper extends Component {
render() {
return <WrappedComponent { ...this.props } />;
}
}
ThemeWrapper.contextTypes = {
theme: PropTypes.object.isRequired
};
return ThemeWrapper;
};
// Using the HOC
class Button extends Component {
render () {
return <button style={{ color: this.context.theme.primaryColor }} />;
}
}
const ThemeButton = Theme(Button);
// Example
<ThemeProvider variables={{ 'primaryColor': 'red' }}>
<div>
<ThemeButton />
</div>
</ThemeProvider>
当您使用Redux时,您可以将需要以connect
HOC为主题的每个组件包装起来,并将您的主题信息存储在商店状态中。这是一种共享数据的简单方法,可以避免上下文的复杂性:
class Button extends Component {
render () {
return <button style={{ color: this.props.theme.primaryColor }} />
}
}
const ConnectedButton = connect((state) => ({ theme: state.theme }))(Button);
// Example
// During app setup
store.dispatch(setTheme({ 'primaryColor': 'red' }));
// Later
<div>
<ConnectedButton />
</div>
希望这有帮助。
答案 1 :(得分:1)
对于任何来此发布后的人,here is an excellent guide都介绍了如何通过上下文和挂钩隐式传递道具。这篇文章的简短摘要:
ThemeContext.js:
const ThemeContext = React.createContext({});
export const ThemeProvider = ThemeContext.Provider;
export const ThemeConsumer = ThemeContext.Consumer;
export default ThemeContext;
HomePage.js:
import {ThemeProvider} from './ThemeContext.js';
const HomePage = () => {
const handleClick = e => {};
const currentTheme = {backgroundColor: 'black', color: 'white'};
return (
<ThemeProvider value={currentTheme}>
<MyButton text='Click me!' onClick={handleClick} ... />
...
</ThemeProvider>
);
}
MyButton.js:
import React, { useContext } from 'react';
import ThemeContext from './ThemeContext';
const MyButton = ({text, onClick}) => {
const style = useContext(ThemeContext);
return <button style={style} onClick={onClick}>{text}</button>;
}
答案 2 :(得分:0)
如果您希望创建更高阶的组件,可以参考此http://gaearon.github.io/react-dnd/,但仍需要正确配置组件,以确定是否应该应用高阶组件的道具。< / p>
或者,为什么不创建一个包装组件,如myButton
export default class MyBytton(){
render(){
return <button { 'primaryColor': 'red' } />
}
}
render(){
return <MyButton otherProperty:"foo"/>
}