0. Does it actually work?
react-native-bem
extended stylesheet
styled components
🥇
styled
components
🥇
🥉
extended
stylesheet
bem
StyleSheet.create({
foo: {
margin: 10,
},
bar: {
padding: 20,
}
})
{
1: foo,
2: bar,
}
🥇
styled
components
🥇
🥇
extended
stylesheet
bem
EStyleSheet.create({
$size: 20,
color: '$textColor',
'@media (min-width: 350) and (max-width: 500)': {
text: {
fontSize: '2rem',
}
},
borderRadius: '0.5 * $size'
});
EStyleSheet.build({
$textColor: '#0275d8'
});
import { TEXT_COLOR } from '@globals';
const windowSize = Dimensions.get('window');
const size = 20;
StyleSheet.create({
color: TEXT_COLOR,
text: windowSize.width >= 350 && windowSize.width <= 500 ? 2 : null,
borderRadius: 0.5 * size;
});
🤷♂️
const StyledView = styled.View`
background-color: papayawhip;
`;
const StyledText = styled.Text`
color: palevioletred;
`;
const RotatedBox = styled.View`
transform: rotate(90deg);
text-shadow-offset: 10px 5px;
font-variant: small-caps;
margin: 5px 7px 2px;
`;
Imagine how you'd write the property in React Native, guess how you'd transfer it to CSS, and you're probably right
Probably?!
🤷♂️
🥇
styled
components
❌
extended
stylesheet
bem
❌
b = bem(selector, this.props, styles);
class Button extends Component {
render() {
const style = getStyle(this.props.scale)
return (
<View style={style.button} />
);
}
}
const getStyle = (scale = 1) => (
EStyleSheet.create({
$scale: scale,
button: {
width: 100,
height: 20,
marginLeft: 10
}
});
);
/*
A new stylesheet is created
on every render… unless…
*/
import memoize from 'lodash/memoize';
const getStyle memoize((scale = 1) => (
EStyleSheet.create({
$scale: scale,
button: {
width: 100,
height: 20,
marginLeft: 10
}
});
));
const Button = styled.button`
background: ${props => props.primary ? 'palevioletred' : 'white'};
color: ${props => props.primary ? 'white' : 'palevioletred'};
`;
🥇
styled
components
🥈
🥉
extended
stylesheet
bem
import styles from './styles';
…
onHideUnderlay = () => { this.setState({ SisPressed: false }); }
onShowUnderlay = () => { this.setState({ SisPressed: true }); }
b = bem(selector, { ...this.props, ...this.state }, styles);
…
<TouchableHighlight
onHideUnderlay={this.onHideUnderlay}
onPress={this.onPress}
onShowUnderlay={this.onShowUnderlay}
>
<View style={this.b('button')}>
<Text style={this.b('button__text')}>
{this.props.text}
</Text>
</View>
</TouchableHighlight>
import styles from './styles';
…
onHideUnderlay = () => { this.setState({ isPressed: false }); };
onShowUnderlay = () => { this.setState({ isPressed: true }); };
…
<TouchableHighlight
onHideUnderlay={this.onHideUnderlay}
onPress={this.onPress}
onShowUnderlay={this.onShowUnderlay}
>
<View style={[
styles.button, this.state.isPressed && styles.buttonIsPressed
]}>
<Text style={[
styles.button__text,
this.state.isPressed && styles.buttonIsPressedButton__text,
]}>
{this.props.text}
</Text>
</View>
</TouchableHighlight>
const StyledButton = styled.View`
align-items: center;
background-color: ${(props) => (props.pressed ? t('highlight') : t('secondary'))};
border-color: ${(props) => (props.pressed ? t('highlight') : t('secondary'))};
border-width: 2;
flex-direction: row;
border-radius: 5;
justify-content: center;
height: ${Platform.OS === 'ios' ? 48 : 50};
paddingHorizontal: ${s('small')};
width: 100%;
`;
const StyledButtonText = styled.Text`
color: ${(props) => (props.pressed ? c('gray 222222') : c('white'))};
font-size: 15;
letter-spacing: 1.9;
text-align: center;
width: 100%;
`;
…
<TouchableHighlight
onHideUnderlay={this.onHideUnderlay}
onPress={this.onPress}
onShowUnderlay={this.onShowUnderlay}
>
<StyledView pressed={this.state.isPressed}>
<StyledText pressed={this.state.isPressed}>
{this.props.text}
</StyledText>
</View>
</TouchableHighlight>
const StyledPressedButton = StyledButton.extend`
background-color: ${t('highlight')};
border-color: ${t('highlight')};
`;
const StyledPressedButtonText = StyledButtonText.extend`
color: ${c('gray 222222')};
`;
…
render() {
const ButtonComponent = this.state.isPressed ?
StyledPressedButton : StyledButton;
const ButtonTextComponent = this.state.isPressed ?
StyledPressedButtonText : StyledButtonText;
return (
<TouchableHighlight
onHideUnderlay={this.onHideUnderlay}
onPress={this.onPress}
onShowUnderlay={this.onShowUnderlay}
>
<ButtonComponent>
<ButtonTextComponent>
{this.props.text}
</ButtonTextComponent>
</ButtonComponent>
</TouchableHighlight>
);
}
🥇
styled
components
🥈
🥉
extended
stylesheet
bem
class Button extends Component {
render() {
return (
<TouchableHighlight>
<View>
<Text>
{this.props.text}
</Text>
</View>
</TouchableHighlight>
);
}
}
class App extends Component {
render() {
return (
<Button style={{ margin: 20 }} />
);
}
}
class Button extends Component {
render() {
return (
<TouchableHighlight>
<View style={this.b('button')}>
<Text>
{this.props.text}
</Text>
</View>
</TouchableHighlight>
);
}
}
class App extends Component {
render() {
return (
<Button style={{ margin: 20 }} />
);
}
}
class Button extends Component {
render() {
return (
<TouchableHighlight>
<View style={this.props.style}>
<Text>
{this.props.text}
</Text>
</View>
</TouchableHighlight>
);
}
}
class App extends Component {
render() {
return (
<Button style={{ margin: 20 }} />
);
}
}
class Button extends Component {
render() {
return (
<TouchableHighlight>
<View style={[
styles.button,
this.state.isPressed && styles.buttonIsPressed,
this.props.style,
]}>
<Text>
{this.props.text}
</Text>
</View>
</TouchableHighlight>
);
}
}
class App extends Component {
render() {
return (
<Button style={{ margin: 20 }} />
);
}
}
class Button extends Component {
render() {
return (
<TouchableHighlight>
<StyledButton style={this.props.style}>
<StyledButtonText>
{this.props.text}
</StyledButtonText>
</StyledButton>
</TouchableHighlight>
);
}
}
class App extends Component {
render() {
return (
<Button style={{ margin: 20 }} />
);
}
}
🥇
styled
components
🥈
🥉
extended
stylesheet
bem
team-list {}
team-list--under-a-certain-condition {}
team-list.in-a-particular-state {}
team-list__title {}
team-list--under-a-certain-condition team-list__title {}
team-list.in-a-particular-state team-list__title {}
team-list-player {}
team-list-player__name {}
team-list-player__position {}
<StyledTeamList />
<StyledTeamList underACertainCondition />
<StyledTeamList inAParticularState />
<StyledTeamListTitle />
<StyledTeamListTitle underACertainCondition />
<StyledTeamListTitle inAParticularState />
<StyledTeamListPlayer />
<StyledTeamListPlayerName />
<StyledTeamListPlayerPosition />
🥇
styled
components
🥈
🥉
extended
stylesheet
bem
<Button Mfoo="bar" Sbaz={true} />
🤷♂️
Props = {
MbgColor: string // eslint-disable-line no-unused-props
}
🤢
{props.MbgColor === 'NRLAccount' ? 'INSIDE PASS' : props.text}
b = bem(selector, {
MbgColor: this.props.userAccess,
}, styles);
🥇
styled
components
🥈
🥉
extended
stylesheet
bem
🥇
styled
components
🥈
🥉
extended
stylesheet
bem
7
0
1
2
3
2
2
2
3
style
prop is applied, child blocks also apply it
'foo bar'
) in the style name couldn't.
All of the good bits, none of the bad
import vogue from 'react-native-vogue';
class Button extends Component {
render() {
return (
<TouchableHighlight
onHideUnderlay={this.onHideUnderlay}
onPress={this.onPress}
onShowUnderlay={this.onShowUnderlay}
>
<View style={this.props.v('root')}>
<StyledText
style={this.props.v('text')}
weight="600"
>
{this.props.text}
</StyledText>
</View>
</TouchableHighlight>
);
}
}
export default vogue(Button, styles);
export default vogue(Button, styles, (props) => ({
'--on-light': props.onLight,
'--size': props.size,
'--type': props.type,
'.is-pressed': false,
}));
// Used in the component
type Props = {
text: string,
url: string,
onPress: () => mixed,
};
// Used to affect styles
type VogueProps = {
onLight: boolean,
size: string,
type: string,
};
class Button extends Component<Props> {
…
}
export default vogue(Button, styles, (props: Props & VogueProps) => ({
'--on-light': props.onLight,
'--size': props.size,
'--type': props.type,
'.is-pressed': false,
}));
class Button extends Component<Props> {
onHideUnderlay = () => {
this.props.inVogue({ '.is-pressed': false });
}
onShowUnderlay = () => {
this.props.inVogue({ '.is-pressed': true });
}
render() {
return (
<TouchableHighlight
onHideUnderlay={this.onHideUnderlay}
onShowUnderlay={this.onShowUnderlay}
/>
);
}
}
export default StyleSheet.create({
'root': {
…
},
'--type-hollow': {
…
},
'.is-pressed': {
…
},
'text': {
…
},
'--on-light text': {
…
},
'--type-hollow text': {
…
},
'--size-14 text': {
…
},
'.is-pressed text': {
…
},
});
type Props = {
text: string,
uppercase: boolean,
userAccess: string,
};
type VogueProps = {
banner: boolean,
bgColor: string,
fontSize: string,
};
export default vogue(TopicTag, styles, (props: Props & VogueProps) => ({
'--banner': props.banner,
'--bg-color': props.bgColor || props.userAccess,
'--font-size': props.fontSize,
}));
<TopicTag MbgColor={props.userAccess} />
…
{props.MbgColor === 'NRLAccount' ? 'INSIDE PASS' :
props.uppercase ? props.text.toUpperCase() : props.text
}
<TopicTag userAccess={props.userAccess} />
…
{props.userAccess === 'NRLAccount' ? 'INSIDE PASS' :
props.uppercase ? props.text.toUpperCase() : props.text
}