DEV Community

AlanRmachado
AlanRmachado

Posted on

Iniciando com styled-components (React Native)

Eae Reacteros, vamos aprender a usar algo fantástico que facilita muito quando o papo é "Estilização" e "React"?

Introdução

Quando eu iniciei no React Native, eu particularmente não gostava da forma de estilizar, pois estava acostumado com o jeito web, saca? Css e etc. Foi aí que encontrei essa fantástica alternativa: styled components.

Além de você estilizar usando praticamente css, ele facilita em muitas outras coisas como passagem de props para mudança de estilo e separação do estilo por componente. Enfim, mais um monte de opções. Sugiro que dê uma boa lida na documentação, pois, além de fácil é bem completa.

Um ponto importante a ser ressaltado é que essa lib não é só para React Native, ela serve para React.js também.

SPOILER: vamos usar o mesmo projeto de checkbox do artigo anterior. Se você perdeu, corre lá : https://dev.to/alanrmachado/criando-seu-proprio-componente-checkbox-no-react-native-3np6

Então, bora lá.

Dependências

Partindo do princípio de que iremos usar o mesmo projeto do artigo anterior, nossa única nova dependência é o styled-components. É simples de instalar, basta seguir a instruções do link a seguir : https://styled-components.com/docs/basics#installation

E finalmente, código.

Na mesma pasta do componente CheckBox, crie um arquivo chamado styles.js.

Eu costumo sempre ter uma pasta por componente, e nela, eu tenho dois arquivos. O index.js que é o componente em si, e o styles.js que é onde fica todo o style desse componente. Acredito que a nível organização, seja uma boa prática.

"Falou demais já, não é Alan???". Foi mal, Reacteros, vamos codar =).

Abra o arquivo styles.js e importe o styled-components, assim:

import styled from "styled-components/native"

"Alan, por que tem esse /native no final?". Lembra que eu disse que essa lib serve para o React.js também? Pois é, tá aí o divisor de águas. Se for usar em um projeto React.js importe sem o /native, beleza?

Lembram como era nosso componente? Não? o.O

Ok, era assim :

 <View style={styles.WrapperCheckBox}>

      <TouchableOpacity onPress={handleChange} style={[
        styles.CheckBox,
        { borderColor: props.checkColor ? props.checkColor : '#fff' }
      ]}>

        {
          props.value ? <Icon name="check"
            style={{
              fontSize: 16,
              color: props.iconColor ? props.iconColor : '#fff'
            }}
          /> : null
        }

      </TouchableOpacity>

      <Text style={[styles.LabelCheck, props.labelStyle]}>
        {props.label}
      </Text>
    </View>

Indo aos poucos, vamos pegar nosso primeiro elemento, o WrapperCheckBox, para começarmos a brincar.

Sabe o que é bacana do styled components? É que basicamente ele cria, como eu costumo dizer, micro componentes já com o estilo certo. Ou seja, você não precisa ter um código cheio de views com a propriedade style sendo preenchida por um objeto que você criou ali, aqui, acolá... Sei lá. A questão é que você pode trocar isso:

  <View style={styles.WrapperCheckBox}>
  </View>

Facilmente por isso:

  <WrapperCheckBox>
  </WrapperCheckBox>

Sacou o que há de mais lindo nisso? "Mas Alan, COOOMOOO?".

Eu explico. Mãos a massa:

Pegue a farinha de trigo... Ops, quer dizer, abra o arquivo styles e comece digitando o seguinte código:

export const WrapperCheckBox = styled.View`

`

Dois pontos importantes.

O primeiro, é que você está fazendo um estilo que será usado em outro arquivo, portanto, você precisa exportá-lo. Até aqui, ok?

Outro ponto é, esse "styled" é o mesmo que importamos logo a cima. É como se esse styled guardasse praticamente quase todos os componentes de design que podemos importar do react-native. Basta colocar um ponto e buscar o componente que queremos criar. Nesse caso, precisamos de uma View. Por isso do "styled.View". Se fosse um Text, faríamos "styled.Text". De boa, né?

Dentro das aspas é onde colocamos as propriedades css desse componente. Vamos fazer o mesmo estilo que antes fizemos usando o StyleSheet, mas agora como se fosse css. Vai ficar assim:


export const WrapperCheckBox = styled.View`
  flex-direction : row;
  align-items: center;
`

Lembre-se, estamos realmente escrevendo css, portanto, a sintaxe deve ser a mesma. Ou seja, o estilo não é um objeto, portanto, ao final de cada instrução se usa ponto e virgula (;) e não (,). Se o row estivesse envolvido em uma aspas, daria erro, pois no css isso não existe. Beleza? Tudo bem até aqui?

Agora vamos a parte emocionante, bora ajustar no arquivo principal do componente.

Primeiro, temos que importar esse WrapperCheckBox. Agora os importes do componente deve estar assim:

import React from 'react';
import PropTypes from "prop-types"
import Icon from "react-native-vector-icons/FontAwesome"
import { View, TouchableOpacity, Text, StyleSheet } from 'react-native';
import { WrapperCheckBox } from "./styles" // Esse é o nosso "micro componente"

Agora é só substituir. Vai ficar assim:

<WrapperCheckBox>
      <TouchableOpacity onPress={handleChange} style={[
        styles.CheckBox,
        { borderColor: props.checkColor ? props.checkColor : '#fff' }
      ]}>

        {
          props.value ? <Icon name="check"
            style={{
              fontSize: 16,
              color: props.iconColor ? props.iconColor : '#fff'
            }}
          /> : null
        }

      </TouchableOpacity>

      <Text style={[styles.LabelCheck, props.labelStyle]}>
        {props.label}
      </Text>
    </WrapperCheckBox>

Animal, né?

Conseguiu ver a vantagem de usar style components? Primeiro que você escreve css para estilizar, segundo que, olha só como fica mais organizado o código. Não temos mais uma View, com um style e etc. Agora temos um simples cara chamado "WrapperCheckBox" e só. O estilo dele está em outro arquivo, facilitando e muito a manutenção.

Continuando...

Agora que conseguimos montar nosso primeiro estilo usando o styled-components, vamos para o próximo cara que devemos mexer. Que é o TouchableOpacity! Sim, meus amigos reacteros, é ele.

Vamos seguir o mesmo procedimento. Vá até o arquivo styles e crie-o. Eu sei que você consegue. Vai lá. Te espero.

Show, você deve ter feito dessa forma, certo?

export const CheckButtom = styled.TouchableOpacity`
  width: 25px;
  height: 25px;
  border-width: 1px;
  justify-content: center;
  align-items: center;
`

Parabéns, ficou top! É isso mesmo que tínhamos que fazer :)

Agora vamos importar. Vai ficar assim:

import React from 'react';
import PropTypes from "prop-types"
import Icon from "react-native-vector-icons/FontAwesome"
import { View, TouchableOpacity, Text, StyleSheet } from 'react-native';
import { WrapperCheckBox, CheckButtom} from "./styles"

Agora é só substituir não é mesmo? Não.

"Ué, Alan. Por quê?". Analisando essa view, lááááá no componente, podemos ver que ela tem um ternário na propriedade style, que altera seu border-color dependendo do que vem na props, certo? Então, como fazemos isso com o styled component?

Bom, vejo duas formas.

A primeira é manter a propriedade style e deixar praticamente como antes. Aliás, não comentei até agora, mas você continua podendo fazer estilos inline, mesmo sendo um cara criado com styled-components. Então, ficaria assim:

 <WrapperCheckBox>

      <CheckButtom onPress={handleChange} style={{ borderColor: props.checkColor ? props.checkColor : '#fff' }}>

        {
          props.value ? <Icon name="check"
            style={{
              fontSize: 16,
              color: props.iconColor ? props.iconColor : '#fff'
            }}
          /> : null
        }

      </CheckButtom>

      <Text style={[styles.LabelCheck, props.labelStyle]}>
        {props.label}
      </Text>

    </WrapperCheckBox>

Legal, né? Sim, mas tem uma opção mais legal ainda =)

Esses "micro componentes" podem receber props também, sabia? Pois é. Então, porque não mandamos essa props direto para o estilo e lá ele resolve essa questão da cor, heim? Faremos isso então. Corre lá pro arquivo styles e vamos preparar isso.

Antes de mais nada, você percebeu que há um template string na sintaxe de criação desse micro componente, não é mesmo? E como conseguimos inserir código javascript dentro dessa aspas? Simples, usando esse cara aqui ---> ${ código aqui }

Na prática, vamos mandar a props "checkColor" direto para esse micro componente lidar com a cor. Para isso, vamos deixa o estilo dessa forma:

export const CheckButtom = styled.TouchableOpacity`
  width: 25px;
  height: 25px;
  border-width: 1px;
  justify-content: center;
  align-items: center;
  border-color :  ${({ checkColor }) => checkColor ? checkColor : '#fff'}
`

Ou seja, estou usando a desestruturação para pegar somente a propriedade checkColor e verifico, se ela existe, eu acrescento de forma dinâmica o valor do border-color, atribuindo a cor que veio via props. Caso contrário, a cor será branca.

Se você quer se aprofundar mais nas maneiras de passar props, atributos e etc, indico fortemente a documentação do styled-components, que é bem completa.
https://styled-components.com/docs

Veja que temos um ícone também, cuja o qual foi importado do "react-native-vector-icons/FontAwesome".

"Alan, o styled componente tem View, Text, TouchableOpacity e etc. Ele tem esse ícone que usamos também?". A resposta é não. "Mas então, como transformamos esse cara em um style-component?". É simples, meu caro. O style-components nos proporciona uma maneira de transformar qualquer desses carinhas em um styled component. Vamos agora aplicar isso para você entender melhor.

Vai lá no arquivo styles e importa esse ícone. Após isso, crie um styled component chamado IconCheck com as mesmas características de estilo.

Vamos também deixar preparado, assim como fizemos para o componente anterior, a cor dinâmica, baseado na props iconColor.

Não se assuste, mas o resultado final do estilo fica assim:

export const IconCheck = styled(Icon)`
  font-size : 16px;
  color :  ${({ iconColor }) => iconColor ? iconColor : '#fff'};
`

Ou seja, perceba que eu passei o componente que o styled component não tem, dessa forma --> export const IconCheck = styled(Aqui vai o componente icon importado do "react-native-vector-icons/FontAwesome"). Simples, não é?

Agora vamos importar esse micro componente que acabamos de criar e substituir no nosso componente principal. Vai ficar assim:

   <WrapperCheckBox>
      <CheckButtom onPress={handleChange} checkColor={props.checkColor}>
        {
          props.value ? <IconCheck color={ props.iconColor} name="check"/> : null
        }

      </CheckButtom >

      <Text style={[styles.LabelCheck, props.labelStyle]}>
        {props.label}
      </Text>
    </WrapperCheckBox>

Bom, vamos para o último estilo a ser criado, a label.

No caso da label, nós não precisamos preparar no styled component para que receba uma props. "Mas Alan, a label recebe uma props chamada labelStyle". Lembra que eu disse que por mais que criamos um styled component, o mesmo ainda continua podendo receber styles inline? Pois bem, como essa props é realmente um objeto de estilo, basta mantermos a propriedade style recebendo essa props naturalmente.

Então, o estilo ficará assim:

export const LabelCheck = styled.Text`
  color: #fff;
  margin-left: 6px;
`

Agora vamos importar esse micro componente e fazer a substituição em nosso componente principal, que ficará assim:

    <WrapperCheckBox>

      <CheckButtom onPress={handleChange} checkColor={props.checkColor}>
        {
          props.value ? <IconCheck color={props.iconColor} name="check" /> : null
        }
      </CheckButtom>

      <LabelCheck style={props.labelStyle}>
        {props.label}
      </LabelCheck>

    </WrapperCheckBox>

Só para finalizar, veja como ficou meu arquivo styles:

import styled from "styled-components/native"
import Icon from "react-native-vector-icons/FontAwesome"

export const WrapperCheckBox = styled.View`
  flex-direction : row;
  align-items: center;
`
export const CheckButtom = styled.TouchableOpacity`
  width: 25px;
  height: 25px;
  border-width: 1px;
  justify-content: center;
  align-items: center;
  border-color :  ${({ checkColor }) => checkColor ? checkColor : '#fff'};
`

export const IconCheck = styled(Icon)`
  font-size : 16;
  color :  ${({ iconColor }) => iconColor ? iconColor : '#fff'};
`

export const LabelCheck = styled.Text`
  color: #fff;
  margin-left: 6px;
`

Finalizando

Agora que já terminamos, vamos apagar os imports desnecessários e o StyleSheet que criamos no post anterior.

Nosso componente ficará:

import React from 'react';
import PropTypes from "prop-types"
import { WrapperCheckBox, CheckButtom, IconCheck, LabelCheck } from "./styles"

export default function CheckBox(props) {

  function handleChange() {
    const { onChange } = props;
    if (onChange) {
      return onChange();
    }
  }

  return (
    <WrapperCheckBox>
      <CheckButtom onPress={handleChange} checkColor={props.checkColor}>
        {
          props.value ? <IconCheck color={props.iconColor} name="check" /> : null
        }
      </CheckButtom>

      <LabelCheck style={props.labelStyle}>
        {props.label}
      </LabelCheck>
    </WrapperCheckBox>
  );
}

CheckBox.propTypes = {
  label: PropTypes.string,
  labelStyle: PropTypes.object,
  iconColor: PropTypes.string,
  onChange: PropTypes.func,
  value: PropTypes.boolean,
  cehckColor: PropTypes.string
}

E é isso aí, Reacteros. Nos vemos no próximo post :)

Discussion (1)

Collapse
alexdpaiva profile image
Alex Paiva

Cara ficou bem legal e mais simples de estilizar, parabéns, no aguardo de novos artigos.