A grande vantagem que o React native nos traz, é tornar único o código tanto para Android, quanto para IOS. Não só pensando nos dispositivos móveis, graças ao React, o código pode ser utilizado no desenvolvimento web. Mas quando chegamos na parte de estilização, podemos ter que nos acostumar e perceber que nessa parte a diferença do que estamos acostumados a ver no desenvolvimento web, é maior que o esperado.
Cascading Style Sheets (CSS)
A princípio mexer com estilo no React native, parece ser bem simples. Podemos ver as regras de CSS e que diferente da web, onde as as mesmas são escritas em kebab-case, utilizaremos a sintaxe com CamelCase.
O React Native utiliza o mecanismo de layout de Yoga, que implementa as especificações do flexbox e empresta nomes de regras CSS. Ex:
.text {
font-family: Arial;
font-size: 12px;
}
Que ficaria assim no React native:
const styles = StyleSheet.create({
text: {
fontFamily: "Arial",
fontSize: 12,
}
});
Isso faz com que a escrita do estilo seja muito familiar. Mas depois fica claro que o estilo no React Native é muito diferente do estilo na web. Nomes de regras e flexbox são as únicas coisas que o CSS e o estilo no React Native tem em comum.
Escopo por componente
No navegador, o CSS tem o escopo a nível da página. Para uma aplicação web de uma única página, isso significa que cada folha de estilo afeta a aplicação inteira. As regras de estilos individuais são aplicadas aos elementos no DOM, sendo definidos dentro dos blocos dos seletores. Existem muitas maneiras diferentes de selecionar os elementos DOM.
Com o React Native, os estilos não tem efeito em seu aplicação, a menos que você os passe especificamente aos seus componentes. Não existe um conceito de seletor
porque os componentes e os estilos estão bem acoplados. Isso significa que você pode usar o mesmo nome para estilos em várias folhas de estilo sem causar efeitos colaterais:
const headerStyles = StyleSheet.create({
container: {
backgroundColor: 'red'
}
});
const footerStyles = StyleSheet.create({
container: {
backgroundColor: 'red'
}
});
<Header style={headerStyles.container} />
<Footer style={footerStyles.container} />
Herança
Os estilos não são herdados por padrão. Na web, os elementos DOM herdam alguns dos estilos dos pais por padrão. Estes são principalmente estilos relacionados a texto, e isso significa que você pode fazer:
<style>
.container {
font-family: Arial;
font-size: 12px;
}
</style>
<div class="container">
<h1>Title</h1>
<div>
<p>Test with <strong>text</strong></p>
</div>
</div>
Que é equivalente a:
const styles = StyleSheet.create({
container: {
fontFamily: 'Arial',
fontSize: 12,
},
bold: {
fontWeight: '700',
}
});
<View>
<Text style={styles.container}>Title</Text>
<View>
<Text style={styles.container}>Test with <Text style={styles.bold}>text</Text></Text>
</View>
</View>
Os componentes podem para passar propriedades de estilo para os componentes filho. É o caso do <Text />
do React Native. Um componente <Text />
que é filho de outro componente <Text />,
herdará seus estilos:
<Text style={styles.text}>
Text
<Text style={{fontWeight: bold}}>Text</Text>
</Text>
O compartilhamento de estilos de texto com <Text />
tem uso limitado, pois <Text />
não permite que a maioria dos outros componentes React Native sejam seus filhos.
Lógica no estilo
O CSS é muito limitado na sua capacidade de calcular valores. Existem algumas funções que você pode usar, como calc()
e as variáveis CSS são suportadas em navegadores modernos. Além disso, a lógica para calcular estilos dinamicamente precisa ocorrer em outros lugares, sendo compilado com pré-processadores (como SASS).
No React Native, os estilos são definidos em JavaScript. Tendo uma linguagem de programação nos dá uma série de possibilidades.
Assim, temos novos padrões de estilo. Esse é um repositório que vale a pena ver.
Style e StyleSheet
Os estilos só podem ser transmitidos diretamente para um componente, da mesma forma que você passaria estilos para elementos DOM através do atributo style
:
<p style="color: blue;">text</p>
Achou que iria se livrar do estilo inline
? XD
A documentação do React native nos informar mais sobre o style.
O que pode ser novo para você é o StyleSheet, que cria uma folha de estilo a partir de um objeto de estilo, tornando possível se referir a ele por ID ao invés de criar um novo objeto de estilo sempre.
Gerenciando estilos
Pra mim, essa é a parte mais critica. Antes de recorrer a módulos de terceiros, uma escolha minha e um conselho é explorar as possibilidades ao utilizar o React native, principalmente se a ideia é ir para a linha universal (nativo e web).
Mixins
Como utilizamos no pré-processador SASS (meu preferido.. :D), os mixins são uma boa saída para reaproveitamento de código e organização:
export const errorText = {
fontWeight: "700",
color: "red",
};
import { errorText } from "textMixins";
export default StyleSheet.create({
formErrorMessage: {
...errorText,
fontSize: 22,
},
fieldErrorMessage: {
...errorText,
fontSize: 18,
},
});
Estilo global
Como em muitas metodologias de CSS, temos uma boa organização definido o estilo primitivo e o reutilizando em suas folhas de estilo. Ex:
export const COLOR_BLUE = "blue";
export const COLOR_RED = "red";
// ...
export default StyleSheet.create({
blue: { color: COLOR_BLUE },
red: { color: COLOR_RED },
// ...
bg_blue: { backgroundColor: COLOR_BLUE },
bg_red: { backgroundColor: COLOR_RED },
// ...
o_100: { opacity: 1 },
o_90: { opacity: 0.9 },
o_80: { opacity: 0.8 },
// ...
});
Podendo ser usado assim:
import styles from "styles";
class MyComponent extends React.Component {
render() {
return (
<View style={styles.bg_red}>
<Text style={[styles.blue, styles.o_90]}>Text</Text>
</View>
);
}
}
Ou assim:
import { COLOR_BLUE, COLOR_RED } from "styles";
class MyComponent extends React.Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.text}>Text</Text>
</View>
);
}
}
const styles = {
container: {
backgroundColor: COLOR_BLUE,
},
text: {
color: COLOR_RED,
}
}
Teste e busque a melhor solução para o seu projeto. Aqui veremos só algumas possibilidades. Então descubra o seu problema e comece a pensar na solução para a arquitetura.
Muitas vezes, mesmo uma pequena mudança na forma como um componente funciona, significa que os nomes dos estilos não se encaixam. E os problemas podem aparecer e prejudicar o projeto. Então gaste um tempo, testando a necessidade do projeto e a melhor solução de organização e utilização.
Funções auxiliares
Estilos em JavaScript significa que você obtém o poder de uma linguagem de programação em vez de uma linguagem de estilo simples.
// font https://gist.github.com/samueljmurray/eeb9495146ef0aad24f534cecd17487c
import { Dimensions } from "react-native";
// Height
const screenSizes = [
{
name: "xs",
height: 568
},
{
name: "s",
height: 667
}
];
// Example usage:
// screenSize({xs: 8, s: 12}, 16)
// screenSize({s: 12}, 16)
// screenSize({xs: 8}, 16)
export function screenSize(screenSizeOptions, defaultValue) {
const matchedScreenSizes = screenSizes.filter((screenSize) => {
return Dimensions.get("window").height < screenSize.height;
});
let value;
const hasScreenSizeOption = matchedScreenSizes.some((matchedScreenSize) => {
if (screenSizeOptions.hasOwnProperty(matchedScreenSize.name)) {
value = screenSizeOptions[matchedScreenSize.name];
return true;
} else {
return false;
}
});
if (!hasScreenSizeOption) {
value = defaultValue;
}
return value;
Passando contexto para o estilo
Um componente <Button />
, por exemplo, pode aceitar uma propriedade de cor (string) e estilo quando estiver desabilitado (booleano), que afetam o seu estilo:
export default StyleSheet.create({
button: {
backgroundColor: "red",
},
buttonDisabled: {
backgroundColor: "gray",
},
});
import styles from "buttonStyles";
class Button extends React.Component {
render() {
return (
<View style={[
styles.button,
this.props.color && {
backgroundColor: this.props.color
},
this.props.disabled && styles.buttonDisabled,
]}>
// ...
</View>
);
}
}
O problema do exemplo acima, que pode ficar muita lógica misturada (estilo e funcionalidade do componente). Então, vamos deixar a lógica de estilo no seu devido lugar.
export default (props) => StyleSheet.create({
button: StyleSheet.flatten([
{
backgroundColor: "red",
},
props.color && {
backgroundColor: props.color,
},
props.disabled && {
backgroundColor: "gray",
},
]),
});
import styles from "buttonStyles";
class Button extends React.Component {
render() {
const s = styles(this.props);
return (
<View style={s.button}>
// ...
</View>
);
}
}
Mais um exemplo, sem StyleSheet:
class Button extends React.Component {
render() {
const s = styles(this.props);
return (
<View style={s.button}>
// ...
</View>
);
}
}
const styles = props => ({
button: {
backgroundColor: props.disabled ? "gray": (props.color ? props.color : "red"),
},
});
Ficou mais complexo. Simplificando ficaria assim:
class Button extends React.Component {
render() {
const { color, disabled } = this.props;
const buttonStyle = disabled ? styles.button({ color }) : styles.buttonDisabled;
return (
<View style={buttonStyle}>
// ...
</View>
);
}
}
const styles = {
button: props => ({
backgroundColor: props.color ? props.color : "red",
},
buttonDisabled: {
backgroundColor: "gray",
}
});
Esses foram exemplos que seguirmos uma linha antes de avaliar bem o projeto, pode ficar muito complexo, independente do caminho escolhido. O melhor caminho é ver na prática e testar as possibilidades que conseguir.
Conclusão
Testando as abordagens ao estilo no React native, podemos ver a flexibilidade e também muda a forma como pensamos sobre como os estilos podem ser definidos em aplicações baseadas em componentes JavaScript, não apenas no React Native, mas também na web.
Tem muitas bibliotecas para testar:
- Styled components
- Extended StyleSheets for React Native
- Further - algebraic style composition for functional UIs
Então, vamos testar!