In CSS we use the descendant selector to style elements based on their nesting. Thankfully in React we don't need to consider this most of the time because this nesting of elements happens within the bounds of a single component.

However occasionally the nesting of components affects the styles. In these rare cases we can use context to influence styles yielding a user friendly api to our components.

The html structure should looks like:

                    <ButtonGroup isVertical>
<Button element={'a'}>Click</Button>
<Button element={'a'}>Click</Button>
</ButtonGroup>

So what ButtonGroup should do is affect its child elements alignments and styling (marign or padding).

So if html is like:

                    <ButtonGroup>
<Button element={'a'}>Click</Button>
<Button element={'a'}>Click</Button>
</ButtonGroup>

It should looks like:

In the article, only point out 3 important thing, so rest of stuff, go to the github.

1. Styling ButtonGroup component itself, add padding it.

We have a default theme.js file to config the theme:

export default {
color: {
keyColor: '#3f8bae',
textLight: '#fff',
},
number: {
buttonRadius: 5,
buttonGroupSpace: 6,
},
string: {
mainFontFamily: 'sans-serif'
}
}

'buttonGroupSpace' is the one to control the padding for ButtonGroup.

And we have the function to modify style according to the theme ready in hocs.js:

export const themeStyle = mapThemeToStyle => mapProps(
props => {
const { theme, style } = props; return {
...props,
style: [
mapThemeToStyle(theme, props),
style
]
};
}
);

So what we need to do is give 'mapThemeToStyle' fucntion to enable it modify the style according to the theme.

ButtonGroup.js:

import React, {PropTypes} from 'react';

import {
addStyle,
getTheme,
themeStyle
} from './hocs';
import {
setDisplayName,
compose
} from 'recompose';
import Radium from 'radium'; const mapThemeToStyle = ({number}, porps) => ({
padding: (number.buttonGroupSpace || 6) * 1
}); const ButtonGroup = ({ children, ...rest }) => (
<div {...rest}>
{children}
</div>
); const enhance = compose(
setDisplayName('ButtonGroup'),
getTheme,
themeStyle(mapThemeToStyle),
addStyle({
padding: 6,
display: 'flex'
}),
Radium
); export default enhance(ButtonGroup);

Notice that  'themeStyle' can override 'addStyle' function, 'compose' read from buttom to top.

2. Pass context down from ButtonGroup to Button.

For the Buttons inside ButtonGroup, we want each has some margin instead of stick with each other. So we need one way to tell whether the Buttons are inside ButtonGroup or not.

One way is to use Context. From ButtonGroup we provide a context called 'buttonGroup', boolean value.

We can use recompose's withContext method:

import React, {PropTypes} from 'react';

import {
addStyle,
getTheme,
themeStyle
} from './hocs';
import {
setDisplayName,
withContext,
compose
} from 'recompose';
import Radium from 'radium'; const mapThemeToStyle = ({number}, porps) => ({
padding: (number.buttonGroupSpace || 6) * 1
}); const ButtonGroup = ({ children, ...rest }) => (
<div {...rest}>
{children}
</div>
); const enhance = compose(
setDisplayName('ButtonGroup'),
getTheme,
themeStyle(mapThemeToStyle),
withContext(
{buttonGroup: PropTypes.bool}, // define the context type
(props) => ({buttonGroup: true}) // set the value of context
),
addStyle({
padding: 60,
display: 'flex'
}),
Radium
); export default enhance(ButtonGroup);

Now, because the concept of 'Context' is for re-useable. We put 'buttonGroup' context into hocs.js:

import {
getContext
} from 'recompose'; export const getButtonGroup = getContext({
buttonGroup: PropTypes.bool
});

It uses 'getContext' from recompose lib.

Now, in the Button.js, we can get the context on props:

import React from 'react';
import {
mapProps,
compose,
defaultProps,
setDisplayName,
componentFromProp
} from 'recompose';
import Radium from 'radium'; import {
getTheme,
themeStyle,
addStyle,
getButtonGroup
} from './hocs'; const mapThemeToStyle = ({
color,
number,
string
}, props) => {
return {
...(color.keyColor &&
{backgroundColor: color.keyColor} || {}
),
...(props.buttonGroup &&
{margin: number.buttonGroupSpace} || {}
),
color: color.textLight,
borderRadius: number.buttonRadius,
fontFamily: string.mainFontFamily
};
}; const style = {
backgroundColor: 'red',
borderWidth: 0,
borderStyle: 'solid',
boxSizing: 'border-box',
fontFamily: 'sans-serif',
fontSize: 18,
borderRadius: 3,
fontWeight: 100,
padding: 12,
verticalAlign: 'middle',
whiteSpace: 'nowrap',
color: 'white',
alignItems: 'center',
justifyContent: 'center',
textDecoration: 'none',
display: 'flex',
flex: 1,
cursor: 'pointer',
':hover': {
backgroundColor: 'purple'
}
}; const enhance = compose(
getButtonGroup,
getTheme, // using the container's defined theme
themeStyle(mapThemeToStyle), // apply the default theme to the component
addStyle(style),
setDisplayName('Button'),
defaultProps({
element: 'button'
}),
Radium
);
export default enhance(componentFromProp('element'));

Once 'buttonGroup' is true, it will add margin for each Buttons inside ButtonGroup.

3. 'isVertical' prop.

We can add this prop on to the html:

                    <ButtonGroup isVertical>
<Button element={'a'}>Click</Button>
<Button element={'a'}>Click</Button>
</ButtonGroup>

Then in the ButtonGroup.js, we can check that whether this props exists, if yes, then set display direction to 'column' otherwise to 'row'.

import React, {PropTypes} from 'react';

import {
addStyle,
getTheme,
themeStyle
} from './hocs';
import {
setDisplayName,
withContext,
compose
} from 'recompose';
import Radium from 'radium'; const mapThemeToStyle = ({number}, porps) => ({
padding: (number.buttonGroupSpace || ) * ,
flexDirection: porps.isVertical ? 'column': 'row'
}); const ButtonGroup = ({ children, ...rest }) => (
<div {...rest}>
{children}
</div>
); const enhance = compose(
setDisplayName('ButtonGroup'),
getTheme,
themeStyle(mapThemeToStyle),
withContext(
{buttonGroup: PropTypes.bool},
(props) => ({buttonGroup: true})
),
addStyle({
padding: ,
display: 'flex'
}),
Radium
); export default enhance(ButtonGroup);

[Recompose] When nesting affects Style的更多相关文章

  1. 《C Elements of Style》 书摘

    <C Elements of Style> 书摘 学完C语言和数据结构后,虽然能解决一些问题,但总觉得自己写的程序丑陋,不专业.这时候看到了Steve Oualline写的<C El ...

  2. WPF整理-Style

    "Consistency in a user interface is an important trait; there are many facets of consistency,   ...

  3. A CIRCULAR PROGRESSBAR STYLE USING AN ATTACHED VIEWMODEL

    This blog post describes how to re-template the Silverlight ProgressBar control to render a circular ...

  4. BootStrap入门教程 (一) :手脚架Scaffolding(全局样式(Global Style),格网系统(Grid System),流式格网(Fluid grid System),自定义(Customing),布局(Layouts))

    2011年,twitter的“一小撮”工程师为了提高他们内部的分析和管理能力,用业余时间为他们的产品构建了一套易用.优雅.灵活.可扩展的前端工具集--BootStrap.Bootstrap由MARK ...

  5. linux c coding style

    Linux kernel coding style This is a short document describing the preferred coding style for the lin ...

  6. [中英对照]Linux kernel coding style | Linux内核编码风格

    Linux kernel coding style | Linux内核编码风格 This is a short document describing the preferred coding sty ...

  7. Google JavaScript Style Guide

    转自:http://google.github.io/styleguide/javascriptguide.xml Google JavaScript Style Guide Revision 2.9 ...

  8. [Recompose] Compute Expensive Props Lazily using Recompose

    Learn how to use the 'withPropsOnChange' higher order component to help ensure that expensive prop c ...

  9. [Recompose] Show a Spinner While a Component is Loading using Recompose

    Learn how to use the 'branch' and 'renderComponent' higher-order components to show a spinner while ...

随机推荐

  1. 原生js大总结三

    021.定义函数的几种方式   1.关键字函数:function fnName(){};   2.字面量函数:var fn = function(){};   3.构造函数:var fn = new ...

  2. Tomcat redis 配置

    http://www.cnblogs.com/interdrp/p/4868740.html http://blog.csdn.net/qq584852076/article/details/4650 ...

  3. Vim 模式及常用命令整理

    VIM 命令     以:和/开头的命令都有历史纪录,可以首先键入:或/然后按上下箭头来选择某个历史命令.   vim的模式 基本上可以分为3种模式,分别是命令模式(command mode).插入模 ...

  4. 具体解释。。设计模式5——DAO。。studying

    设计模式5--DAO ★ 场景和问题 在Java程序中,常常须要把数据持久化.也须要获取持久化的数据,可是在进行数据持久化的过程中面临诸多问题 (如:数据源不同.存储类型不同.供应商不同.訪问方式不同 ...

  5. 大战C100K之-Linux内核调优篇--转载

    原文地址:http://joyexpr.com/2013/11/22/c100k-4-kernel-tuning/ 早期的系统,系统资源包括CPU.内存等都是非常有限的,系统为了保持公平,默认要限制进 ...

  6. autohotkey word getfullname (ComObjActive)

    直接使用ComObjActive

  7. POSIX 多线程编程及理解

    最近开发基于ZYNQ的嵌入式linux程序,涉及到多线程使用,将一些内容整理如下: POSIX多线程编程最为基础和重要的可以分为两部分: 线程操作-Thread Management 线程同步-Syn ...

  8. XML Parser Errors See Details for more Information XML Parser Error on line 1: Document root ele

    1.错误描写叙述 XML Parser Errors See Details for more Information XML Parser Error on line 1: Document roo ...

  9. 1 Spring Cloud Eureka服务治理(上)

    注:此随笔为读书笔记.<Spring Cloud微服务实战>,想学习Spring Cloud的同伴们可以去看看此书,里面对源码有详细的解读. 什么是微服务? 微服务是将一个原本独立的系统拆 ...

  10. 使用XX-Net永久访问真正的互联网

    XX-Net基于GoAgent(代理软件),使用谷歌App Engine(GAE)代理服务器通过防火墙,是github上的一个开源项目. https://github.com/XX-net/XX-Ne ...