Flutter Formz Explained – O curso intensivo completo
O Formz é um pacote Dart desenvolvido pela Very Good Ventures para simplificar a representação e a validação de formulários em aplicativos Dart. Esse pacote fornece uma representação de formulário unificada que facilita o gerenciamento dos dados dos campos de formulário e de seu status de validação.
Depois de entender completamente como usá-lo, você nunca mais vai querer perdê-lo.
E, por isso, vamos dar uma olhada profunda no Formz hoje!
Vamos começar!
Conteudo
Instalação
A primeira coisa que temos de fazer depois de criar nosso aplicativo é adicionar o Formz. Para isso, usaremos o comando flutter pub add formz. A versão do formz no momento da redação deste artigo é a 0.7.0, mas é bem provável que este tutorial também funcione se você usar uma versão mais recente, pois os princípios básicos não serão alterados.
Criar um módulo do Formz
O Formz é estruturado em modelos, em que cada módulo valida coisas diferentes. Por exemplo, um módulo pode ser usado para validar um endereço de e-mail, uma senha ou uma data. A aparência é a seguinte:
import 'package:formz/formz.dart'; // Isso representa todos os estados ou campos errados que podem ter. // Uma senha pode ser muito curta, não ter nenhum dígito ou letra maiúscula. enum PasswordInputError { tooShort, noDigit, noUppercase } class PasswordInput extends FormzInput<String, PasswordInputError> { // PasswordInput.pure representa uma entrada de formulário não modificada const PasswordInput.pure() : super.pure(''); // Enquanto o super.dirty representa uma entrada de formulário modificada const PasswordInput.dirty({String value = ''}) : super.dirty(value); // Substituir o validador para lidar com a validação de um determinado valor de entrada. @override PasswordInputError validator(String value) { // Essa parte é onde estará toda a nossa lógica de validação } }
Talvez você tenha uma pergunta: O que o .pure e o .dirty fazem?
É bem simples: Digamos que você tenha um campo de texto. Ao inicializar o widget, você usa PasswordInput.pure()
, porque o usuário ainda não inseriu nada. Quando o usuário digita algo no campo de texto, você usa PasswordInput.dirty(value: 'Inputted Value')
. Portanto, dirty é basicamente uma forma de dizer que a entrada foi alterada. E isso ajudará a alterar o estado dos botões (por exemplo, de desativado para ativado) ou outros tipos de coisas.
Agora que sabemos disso, é claro que queremos validar nossa entrada.
Para o nosso exemplo de senha, isso poderia ser algo assim:
class PasswordInput extends FormzInput<String, PasswordInputError> { // [...] - form input representations @override PaswordInputError? validator(String value) { // Verifique se a senha é muito curta if (value.length < 8) { return PasswordInputError.tooShort; } // Verificar se a senha contém um dígito if (!value.contains(RegExp(r'[0-9]'))) { return PasswordInputError.noDigit; } // Verificar se a senha contém uma letra maiúscula if (!value.contains(RegExp(r'[A-Z]'))) { return PasswordInputError.noUppercase; } // Se tudo estiver bem, retorne null return null; } }
É isso aí! Você terminou. Bem… em parte. É claro que precisamos interagir com nossa entrada:
Interagir com o FormzInput
Primeiro, precisamos criar uma variável que armazene nossa PasswordInput
:
PasswordInput passwordInputValue = PasswordInput.pure();
Como já foi dito acima, quando o usuário digita algo no campo de texto, simplesmente atribuímos um novo valor à variável:
passwordInputValue = PasswordInput.dirty(value: newValue);
Agora, com tudo isso configurado, podemos finalmente usar o formz de forma adequada:
// Retorna o valor da entrada print(passwordInputValue.value); // Verifica se a entrada é válida ou não. // Se o valor retornado de seu validador for nulo, ele é válido. Se não for, não é. print(paswordInputValue.isValid); print(PasswordInputValue.isNotValid); // Retorna o erro de sua entrada. Se for nulo, a entrada é válida. // Exemplo de saída: PasswordInputError.tooShort print(passwordInputValue.error);
Especialmente o último, passwordInputValue.error
, vai ajudá-lo tremendamente, aumentando a experiência do usuário. Você não precisa apenas dar a ele uma mensagem dizendo “Sua senha está incorreta”, mas agora pode dizer facilmente “Sua senha precisa ter pelo menos 8 caracteres”, “Você precisa incluir pelo menos um número” etc.
E esse é o poder do Formz. A construção do nosso modelo minúsculo lhe dá muito controle sobre o formulário e sua validação.
Mais recursos do Formz
Validação automática de entrada
Um recurso especial do Formz é a validação automática de várias entradas. Para isso, crie uma classe que estenda o FormzMixin
e adicione como parâmetros diferentes Formz Models:
class LoginForm with FormzMixin { LoginForm({ this.email= const EmailInput.pure(), this.password = const PasswordInput.pure(), }); final EmailInput email; final PasswordInput password; @override List<FormzInput> get inputs => [email, password]; } void main() { // The output would be false in this case print(LoginForm().isValid); }
Cache de validações
O cálculo de algumas validações é bastante caro, por exemplo, se a entrada for bastante complexa. Para evitar validações desnecessárias, você pode simplesmente armazenar em cache as validações de diferentes entradas usando o mixin FormzInputErrorCacheMixin
.
Aqui está um exemplo da documentação do formz:
import 'package:formz/formz.dart'; enum EmailValidationError { invalid } class Email extends FormzInput<String, EmailValidationError> with FormzInputErrorCacheMixin { // É literalmente só isso, nada mais Email.pure([super.value = '']) : super.pure(); Email.dirty([super.value = '']) : super.dirty(); static final _emailRegExp = RegExp( r'^[a-zA-Z\d.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z\d-]+(?:\.[a-zA-Z\d-]+)*$', ); @override EmailValidationError? validator(String value) { return _emailRegExp.hasMatch(value) ? null : EmailValidationError.invalid; } }
Exemplo mais completo usando o package Formz.
// Importando o pacote Formz import 'package:formz/formz.dart'; // Definindo erros de validação de entrada enum NameInputError { empty } // Estendendo FormzInput e fornecendo o tipo de entrada e tipo de erro. class NameInput extends FormzInput<String, NameInputError> { // Chamando super.pure para representar uma entrada de formulário não modificada. const NameInput.pure() : super.pure(''); // Chamando super.dirty para representar uma entrada de formulário modificada. const NameInput.dirty({String value = ''}) : super.dirty(value); // Sobrescrevendo o validador para lidar com a validação de um valor de entrada dado. @override NameInputError? validator(String value) { return value.isEmpty ? NameInputError.empty : null; } } // Interagindo com um FormzInput void main() { const name = NameInput.pure(); print(name.value); // '' print(name.isValid); // false print(name.error); // NameInputError.empty const joe = NameInput.dirty(value: 'joe'); print(joe.value); // 'joe' print(joe.isValid); // true print(joe.error); // null }