[Recompose] When nesting affects Style
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的更多相关文章
- 《C Elements of Style》 书摘
<C Elements of Style> 书摘 学完C语言和数据结构后,虽然能解决一些问题,但总觉得自己写的程序丑陋,不专业.这时候看到了Steve Oualline写的<C El ...
- WPF整理-Style
"Consistency in a user interface is an important trait; there are many facets of consistency, ...
- A CIRCULAR PROGRESSBAR STYLE USING AN ATTACHED VIEWMODEL
This blog post describes how to re-template the Silverlight ProgressBar control to render a circular ...
- BootStrap入门教程 (一) :手脚架Scaffolding(全局样式(Global Style),格网系统(Grid System),流式格网(Fluid grid System),自定义(Customing),布局(Layouts))
2011年,twitter的“一小撮”工程师为了提高他们内部的分析和管理能力,用业余时间为他们的产品构建了一套易用.优雅.灵活.可扩展的前端工具集--BootStrap.Bootstrap由MARK ...
- linux c coding style
Linux kernel coding style This is a short document describing the preferred coding style for the lin ...
- [中英对照]Linux kernel coding style | Linux内核编码风格
Linux kernel coding style | Linux内核编码风格 This is a short document describing the preferred coding sty ...
- Google JavaScript Style Guide
转自:http://google.github.io/styleguide/javascriptguide.xml Google JavaScript Style Guide Revision 2.9 ...
- [Recompose] Compute Expensive Props Lazily using Recompose
Learn how to use the 'withPropsOnChange' higher order component to help ensure that expensive prop c ...
- [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 ...
随机推荐
- CentOS 6 IPv6 关闭方法
http://www.linuxidc.com/Linux/2012-06/63642.htm http://blog.csdn.net/ccscu/article/details/7814028
- Android RxBus的实现及简单使用
RxJava目前已经很火了,如果你尚未了解请看这里.对于RxJava这里不多做介绍.RxBus并不是一个库,而是一种模式.相信大多数开发者都使用过EventBus,作为事件总线通信库,如果你的项目已经 ...
- scrapy-爬取斗图
scrapy-爬取斗图代码 <一> 开局三连杀 1.创建run的文件
- 限制tomcat仅响应本机请求(转)
http://blog.bbzhh.com/index.php/archives/135.html 在VPS上搭建了nginx和tomcat应用,想通过nginx来反向代理127.0.0.1:8080 ...
- DC针对pipeline的优化
set_optimize_register true compile -ultra 调整pipleline各级的组合逻辑,使得各级组合逻辑的延迟跟接近 对非pipeline进行优化: regi ...
- 【例题 6-13 UVA - 1103】Ancient Messages
[链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 每个图案里面的"洞"的个数都是不同的. 则可以根据这个判别每个图像是什么. 先用dfs确定轮廓之后. 再从每个白 ...
- Java BigDecimal的基本使用方法
1.对于不需要任何准确计算精度的数字可以直接使用float或double,但是如果需要精确计算的结果,则必须使用BigDecimal类 2.运算速度比一般的+.-.*./要快 3.基本方 法描 述 ...
- Swift语言之View,Button控件实现小方块在界面上的移动(纯代码实现)
import UIKit class ViewController: UIViewController { var diamonds:UIView! var diamondsXY = CGRectMa ...
- iOS_03_为什么选择ios开发
为什么选择ios开发 为什么要选择移动开发 * 手机将是人类最离不开的设备之一,硬件软件参数也越来越强,应用需求量剧增. * 移动互联(就是将移动通信和互联网二者结合起来)发展迅速,各大公司都对移动互 ...
- sprinng in action 第四版第六章中的ValidationMessages.properties不起作用
文件名必须是ValidationMessages.properties,必须放在类的根目录下