[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 ...
随机推荐
- 洛谷——P3817 小A的糖果
https://www.luogu.org/problem/show?pid=3817 题目描述 小A有N个糖果盒,第i个盒中有a[i]颗糖果. 小A每次可以从其中一盒糖果中吃掉一颗,他想知道,要让任 ...
- js 数组操作大集合
js数组的操作 用 js有非常久了,但都没有深究过js的数组形式.偶尔用用也就是简单的string.split(char).这段时间做的一个项目.用到数组的地方非常多.自以为js高手的自己竟然无从下手 ...
- nagios 安装配置(包含nrpe端)全 (一)
一.nagios安装: 1.安装下面命令: 这是本人监控服务时自己定义插件所用到的几个系统命令.可不安装. (1)iostat:监控磁盘IO信息: apt-getinstall sysstat (2) ...
- home-界面返回上一级功能
1,这个主要是用在actionbar上home键,直接上代码 import android.view.MenuItem; /* Vanzo:zhangshuli on: Mon, 23 Mar 201 ...
- Android Studio com.android.dex.DexException: Multiple dex files define(重复引用包)
如果你用Android Studio开发,并且要用其他项目作为library,这个问题是很容易出现的.出现这个问题的原因是包的重复引用,意思就是在你自己的项目中引用了某个包,而被你作为library的 ...
- Nginx配置GZIP
记录一次解决网站加载慢的问题 一. nginx配置 gzip on;gzip_min_length 1k;gzip_buffers 4 16k;gzip_http_version 1.1;g ...
- js面向对象2--原型
一.原型和原型对象 函数的原型prototype:函数才有prototype,prototype是一个对象,指向了当前构造函数的引用地址. 所有对象都有__proto__属性, 所有的__proto ...
- GO语言学习(十八)Go 语言接口
Go 语言接口 Go 语言提供了另外一种数据类型即接口,它把所有的具有共性的方法定义在一起,任何其他类型只要实现了这些方法就是实现了这个接口. 实例 /* 定义接口 */ type interface ...
- 并发知识与concurrent包
要想进入一线互联网公司,这部分内容必须要会,否则的话,你始终都只能停留在比较low的段位. 关于并发知识,最重要的两个概念一定要搞清楚,那就是可见性和原子性.其中可见性与前面提到的volatile关键 ...
- HDU 2063 过山车 第一道最大二分匹配
http://acm.hdu.edu.cn/showproblem.php?pid=2063 题目大意: m个女生和n个男生一起做过山车,每一排必须一男一女,而每个女孩愿意和一些男生坐一起,, 你要找 ...