React Native - Estilização

Imagem para React Native - Estilização

React nativePostado em  7 min de leitura

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:

Então, vamos testar!