DEV Community

AlanRmachado
AlanRmachado

Posted on • Updated on

Criando seu próprio componente CheckBox no React Native

Eae Reacteros, bora criar um checkbox maneiro e usá-lo em tudo quanto é lugar ? Entããããããããoooo... Vamos lá!

Introdução

Eu sou um grande fã do React e acabo fazendo praticamente todas as minhas aplicações mobile e web com ele. Conforme eu vou desenvolvendo, vou sentindo falta de alguns componentes mais customizáveis, principalmente aqueles que eu sei que irei usar em outras partes do projeto (ou até mesmo em um novo).
Pensando nisso, resolvi fazer esse checkbox. E falando a verdade, eu realmente curto criar meus próprios componentes =).

Bom, já falei demais. Agora vamos botar a mão na massa \o/

Dependências

Teremos duas dependências, react-native-vector-icons e prop-types. os links para instalar são : https://github.com/oblador/react-native-vector-icons e https://github.com/facebook/prop-types

E finalmente, código.

Vamos criar nosso componentezinho e chamá-lo, carinhosamente de, "CheckBox".
A casca fica mais ou menos assim :

import React from 'react';
import { Text, View } from "react-native" 

export default function CheckBox(props) {
  return (
   <Text>Hello World</Text>
  );
}

Nosso componente será basicamente um quadrado vazado e ao lado desse quadrado uma label, certo? Ao clicar no quadrado (que está vazado no momento), terá que aparecer um check e vice-versa. Precisamos então de um botão, algumas views, texto, ícones e estilo. Então, vamos começar com os imports, que serão esses:

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';

Para que a label fique ao lado do quadrado, precisamos criar um container com flex-direction "row", vamos então criar esse estilo e chamar de "WrapperCheckBox".

const styles = StyleSheet.create({
  WrapperCheckBox: {
    flexDirection: "row",
    alignItems: "center"
  }
})

Vamos aproveitar e já criar os estilos do checkbox, que chamaremos de "CheckBox" e da label, que chamaremos de "LabelCheck". Nosso estilo final fica assim:

const styles = StyleSheet.create({
  CheckBox: {
    width: 25,
    height: 25,
    borderWidth: 1,
    justifyContent: "center",
    alignItems: "center"
  },
  WrapperCheckBox: {
    flexDirection: "row",
    alignItems: "center"
  },
  LabelCheck: {
    color: '#fff',
    marginLeft: 6 // Para que não fique colado ao checkbox
  }
})

Agora, vamos preencher nosso componente e colocar os seus conteúdos nos devidos lugares. Será mais ou menos assim : teremos uma View de container, que assumirá o estilo WrapperCheckBox; teremos um botão, que será nosso checkbox e ele assumirá o estilo CheckBox; dentro do botão teremos um ícone; e por fim teremos a label, que será um Text e assumirá o estilo LabelCheck. Ficando assim:

 <View style={styles.WrapperCheckBox}>
    <TouchableOpacity style={styles.CheckBox}>
      <Icon name="check" /> 
    </TouchableOpacity>

    <Text style={styles.LabelCheck}>

    </Text>
 </View>

Até aqui a gente montou toda a parte visual do componente e você deve estar se perguntando: "Tá, e agora como a gente faz isso funcionar?'. Calma! Antes, precisamos falar das props que iremos receber nesse componente. Chega mais, vamos lá!

Devemos prever 6 props para que esse componente esteja completinho, elas são:

Props Tipo Função
Label String Será o nome que aparece ao lado do checkbox
labelStyle Object Estilo da Label
iconColor String Cor do ícone de check
onChange Func Função que será chamada no click do checkbox
value Boolean Será o estado do checkbox
checkColor String Cor do checkbox

Tendo pose dessas informações, vamos criar os proptypes desse componente. "Alan, o que é esse negócio de proptype?". Eu explico. Imagine que você pegue um componente para dar manutenção, e ele recebe uma série de props. Para ajudar, você nem sabe quais e quantas são possíveis. Daí fica difícil, né? É isso que os prop-types resolvem, eles meio que "Documentam" isso no componente.

Após criar os proptypes do nosso componente, ele deve se parecer com isso:

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';


export default function CheckBox(props) {
  return (
    <View style={styles.WrapperCheckBox}>
      <TouchableOpacity style={styles.CheckBox}>
        <Icon name="check" />
      </TouchableOpacity>

      <Text style={styles.LabelCheck}>

      </Text>
    </View>
  );
}

const styles = StyleSheet.create({
  CheckBox: {
    width: 25,
    height: 25,
    borderWidth: 1,
    justifyContent: "center",
    alignItems: "center"
  },
  WrapperCheckBox: {
    flexDirection: "row",
    alignItems: "center"
  },
  LabelCheck: {
    color: '#fff',
    marginLeft: 6
  }
})

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

Tudo certo até aqui, Reacteros? Então, vamos fazer isso funcionar. Simbora!

Lógica do componente

Primeiramente, vamos atualizar nosso componente com os estilos que podem ser dinâmicos, ou seja, aqueles que vem via props.

O nosso checkbox pode mudar de cor dependendo do que vier na props checkColor, certo? Sim. E como faremos isso? Bom, perceba que ele já tem um estilo, mas precisamos acrescentar mais um. Nesse caso, a propriedade style passa a receber um array e não um único objeto. Dessa forma, conseguimos ter múltiplos objetos de estilo.

A cor do nosso checkbox nada mais é que o borderColor. Logo, vamos acrescentar um objeto nesse array contendo essa propriedade junto com um ternário, validando se há essa props, e caso não haja, mantenha a cor branca. Vai ficar assim:

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

Faremos a mesma coisa para a Label. Aproveitando, para colocar a props.label dentro do Text, que será a label recebida. Fica assim:

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

Agora o ícone, e já dá para colocar um fontSize nele. Lembrando que, como ele não tem estilo, não precisamos alterar a propriedade style para um array. Fica assim:

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

Agora vamos a lógica principal do componente.

Primeiramente, devemos garantir que o ícone de check só esteja visível caso a props value seja true, certo? Por conta disso, vamos fazer isso com um ternário. Se for true, mostra o ícone, caso contrário nem apareça. Suma daqui. Tchau.

Vai ficar assim:

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

O 'mostra' e 'não mostra' acontecerá quando o usuário clicar no check, logo, esse evento deve ser chamado onde? Pode falar... No... Se você respondeu no onPress do botão, você... ACERTOU \o/. Lembra da props onChange? Então, essa props será uma função que irá ser passada para o componente, que em tese, irá mudar o estado da props value. Precisaremos chamar esse cara, quando o usuário clicar no checkbox. "Alan, podemos colocar essa função direto no onPress do TouchableOpacity ?". Sim, podemos. Mas lembre-se, pode ser que essa props não exista e daí já viu, né? O usuário vai clicar e BOOMMMM! Nasceu nosso primero bug.

Para nos proteger disso e deixar bem separadinho no componente, vamos criar uma função chamada handleChange e fazer essa validação lá. Basicamente, ele vai verificar se há essa props. Se houver ele invocará essa função, caso contrário, não fará nada.

A função é essa:

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

Usamos um destructuring para pegar a props onChange. "Para ficar chique?". Não, você verá em um momento da sua vida que essa funcionalidade do ES6 é top.

Verificamos se existe de fato um onChange. Se houver invoca, caso contrário, não faça nada. Agora é só chamar essa função no onPress do nosso botão.

E adivinha: é só isso meus Reacteros! Apenas isso. Seu componente deve estar parecido com isso agora:

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';




export default function CheckBox(props) {



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




  return (
    <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>
  );
}

const styles = StyleSheet.create({
  CheckBox: {
    width: 25,
    height: 25,
    borderWidth: 1,
    justifyContent: "center",
    alignItems: "center"
  },
  WrapperCheckBox: {
    flexDirection: "row",
    alignItems: "center"
  },
  LabelCheck: {
    color: '#fff',
    marginLeft: 6
  }
})

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

"Mas Alan, você vai embora sem nos deixar um exemplo de uso?" Claro que não. Se liga:

import React, { useState } from "react";
import { View, StyleSheet, StatusBar } from "react-native"
import CheckBox from "./components/checkbox"




export default function App() {

  const [check, setCheck] = useState(false)

  function handleCheck() {
    setCheck(!check);
  }


  return (
    <>
      <StatusBar backgroundColor="#f47e10" />
      <View style={styles.Container}>

        {/* Esse é o nosso lindo checkBox */}
        <CheckBox
          label="Esse é um checkbox"
          labelStyle={{ color: '#fff', fontSize: 16 }}
          iconColor="#fff"
          checkColor="#fff"
          value={check}
          onChange={handleCheck}
        />


      </View>
    </>
  )
}

const styles = StyleSheet.create({
  Container: {
    flex: 1,
    justifyContent: "flex-start",
    alignItems: "flex-start",
    backgroundColor: '#f47e10',
    padding: 20
  }
})

Imagem do Componente

Para finalizar

Obrigado por terem lido até aqui. Esse foi meu primeiro post e espero que seja o primeiro de muitos. Valeu Reacterooooosss !!!!

Discussion (9)

Collapse
joelee229 profile image
Joel crescêncio de lima sena

Opa Alan, como ficaria se fosse múltiplos checkBox e eu precisasse mandar eles para um backend?

Collapse
alanrmachado profile image
AlanRmachado Author • Edited on

Opa, blz?

Cara, existe algumas formas... A mais simples na minha opinião é o seguinte:

cria um objeto como estado, tipo assim :

const [allChecks, setCheck] = useState({});

cria uma função para abastecer esse objeto :


function handleChecks( property ) {
const obj = allChecks
obj[property] = !obj[property];
setCheck(obj)
}

O parâmetro property vai ser o nome do checkbox. Veja que eu criei dois checkbox, e disse que o valor de um eh check1 e do outro é check2


label="check1"
labelStyle={{ color: '#fff', fontSize: 16 }}
iconColor="#fff"
checkColor="#fff"
value={allChecks.check1}
onChange={()=>handleChecks('check1')}
/>


label="check2"
labelStyle={{ color: '#fff', fontSize: 16 }}
iconColor="#fff"
checkColor="#fff"
value={allChecks.check2}
onChange={()=>handleChecks('check2')}
/>

no final, seu objeto estará igual aos seus checks.

Dica, inicia esse objeto já com todos os checks e seus valores,
mesmo que seja false.

Collapse
viniclefer profile image
Vinicius Fernandes

Salve Alan, por favor como faço para ter múltiplos checkboxs para depois apresentar a quantidades deles através do useState?

Collapse
alanrmachado profile image
AlanRmachado Author

Faaala, Vinícius, blz ?

Putz, cara. Não entendi muito bem sua pergunta. Poderia dar um exemplo ?

Abs!

Collapse
alexdpaiva profile image
Alex Paiva

Ótimo post parabéns,

Collapse
assisneto profile image
Assisneto Damasceno

Parabens mano!

Collapse
alanrmachado profile image
AlanRmachado Author

Valeu, manooooo

Collapse
fernandinhopha profile image
Fernandinho Monteiro

Muito bom !

Collapse
nelsonarcas81 profile image
nelsonarcas81

Excelente exemplo