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. 【Good Bye 2017 C】 New Year and Curling

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 枚举前i-1个圆. 哪些圆和它相交. 取圆心纵坐标最大的那个圆就可以了. [代码] #include <bits/stdc++ ...

  2. 7.3 GROUP BY的“新”功能

    7.3 GROUP BY的"新"功能正在更新内容,请稍后

  3. 解决Cookie乱码

    在Asp.net的HttpCookie中写入汉字,读取值为什么全是乱码?其实这是因 为文字编码而造成的,汉字是两个编码,所以才会搞出这么个乱码出来!其实解决的方法很简单:只要在写入Cookie时,先将 ...

  4. vue-cli打包项目后,可以修改配置文件

    问题: 前端需要修改后台服务器地址url,写好的配置文件会在npm run build 后压缩在一起,传到运行的前端服务器上后,需要到前端打包的源码,找到url地址进行修改.如果不在打包的源码修改,则 ...

  5. Mongodb总结1-启动和Shell脚本

    2013年,还在秒针,当时听说了Mongodb,就学习了下,搞了下HelloWorld.主要是熟悉Mongodb的启动.命令行的Shell脚本.Java访问的CRUD. 今天,由于需要,再次回顾和进一 ...

  6. 【习题 6-1 UVA-673】Parentheses Balance

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 括号匹配. 栈模拟就好. 多种括号也是一样可以做的. [代码] #include <bits/stdc++.h> usi ...

  7. Spring学习总结(7)——applicationContext.xml 配置文详解

    web.xml中classpath:和classpath*:  有什么区别? classpath:只会到你的class路径中查找找文件; classpath*:不仅包含class路径,还包括jar文件 ...

  8. Java Web学习总结(4)——HttpServletResponse对象入门

    Web服务器收到客户端的http请求,会针对每一次请求,分别创建一个用于代表请求的request对象.和代表响应的response对象. request和response对象即然代表请求和响应,那我们 ...

  9. C# SocketAsyncEventArgs类

    Namespace:System.Net.Sockets Assemblies:System.Net.Sockets.dll, System.dll, netstandard.dll (Represe ...

  10. DIV+CSS学习笔记(CSS)

    css基础知识: css样式表的定义 css:(Cascading Style Sheets)层叠样式表: 分类及位置:内部样式-head区域style标签里面 外部样式-link调用 内联样式-标签 ...