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. 18/9/9牛客网提高组Day1

    牛客网提高组Day1 T1 中位数 这好像是主席树??听说过,不会啊... 最后只打了个暴力,可能是n2logn? 只过了前30%  qwq #include<algorithm> #in ...

  2. 关于后台接收参数为null的问题之ajax--contentType

    ajax方法中的参数: contentType:发送至服务器时内容的编码类型,一般默认:application/x-www-form-urlencoded(适应大多数的场合) dataType:预期服 ...

  3. CSDN博客的文章分类和战略规划

    CSDN原创文章已经有300多篇了,现在已经整理了好多个分类目录了. 今天,特别向大家介绍下,每个分类的含义和规划. CSDN博客是我的一个重要的自媒体,也是我的一个战略实践. 我会精心维护这个博客, ...

  4. 微软重生:4年市值U型大逆转,超越谷歌重返巅峰!

    划重点: 智东西(公众号:zhidxcom)文 | 寓扬 在最近的两个星期里,微软和谷歌正在进行一场市值大比拼,双方在7700亿美元上下厮杀正紧,抢夺着全球市值第三大公司的宝座(前两位为市值超过900 ...

  5. sql语句的编程手册 SQL PLUS

    一.SQL PLUS 引言 SQL命令 以下17个是作为语句开头的关键字: alter drop revoke audit grant rollback* commit* insert select ...

  6. 【AtCoder Beginner Contest 074 B】Collecting Balls (Easy Version)

    [链接]h在这里写链接 [题意] 看懂题目之后就会发现是道大水题. [题解] 在这里写题解 [错的次数] 0 [反思] 在这了写反思 [代码] #include <bits/stdc++.h&g ...

  7. 模拟登录QQ推断是否须要验证码

    老生常谈的问题了,在模拟登录之前,推断是否须要验证码: https://ssl.ptlogin2.qq.com/check? uin=QQ号码&appid=1003903&js_ver ...

  8. UVA 10603 - Fill BFS~

    http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&c ...

  9. fdopen:让文件描述符像文件一样使用

    FILE * fdopen(int fildes,const char * mode); fdopen与fopen类似,返回一个FILE *类型的值,不同的是此函数以文件描述符而非文件作为参数. 如果 ...

  10. C++ BYTE数组转字符串

    第一种情况: BYTE[0]=Ox12 BYTE[1]=0x34 BYTE[2]=0x56 最后要转换成字符串123456 另外一种情况: BYTE[0]=Ox12 BYTE[1]=0x34 BYTE ...