Blog


Trabajando con formularios en React Native utilizando TypeScript

TRABAJANDO CON FORMULARIOS EN REACT NATIVE UTILIZANDO TYPESCRIPT

05 / 04 / 2023 Otros

En este artículo, vamos a mostrar cómo trabajar con formularios en React Native utilizando Typescript. A lo largo del artículo, desarrollaremos los componentes, hooks y demás necesarios para implementar un formulario completo y funcional. ¡Empecemos!

Antes de empezar, es importante tener en cuenta que este artículo asume que ya tienes conocimientos básicos de React Native y Typescript.

Componentes de formulario

Empecemos con los componentes de formulario. Estos son los componentes básicos que utilizaremos para construir nuestro formulario. Creamos un archivo FormInput.tsx en el que definimos el componente FormInput:

import React from 'react';
import { TextInput, StyleSheet } from 'react-native';

interface FormInputProps {
  value: string;
  placeholder: string;
  onChangeText: (value: string) => void;
}

const FormInput: React.FC<FormInputProps> = ({ value, placeholder, onChangeText }) => {
  return (
    <TextInput
      style={styles.input}
      value={value}
      placeholder={placeholder}
      onChangeText={onChangeText}
    />
  );
};

const styles = StyleSheet.create({
  input: {
    height: 40,
    borderColor: 'gray',
    borderWidth: 1,
    marginBottom: 10,
    paddingHorizontal: 10,
  },
});

export default FormInput;

Este componente es una envoltura para el componente TextInput de React Native. Se espera que se le proporcione un value, un placeholder y una función onChangeText, que se ejecutará cada vez que el texto del TextInput cambie. El componente de estilo se utiliza para darle un aspecto adecuado.

Ahora, crearemos un archivo FormButton.tsx que definirá el componente FormButton:

import React from 'react';
import { TouchableOpacity, Text, StyleSheet } from 'react-native';

interface FormButtonProps {
  label: string;
  onPress: () => void;
}

const FormButton: React.FC<FormButtonProps> = ({ label, onPress }) => {
  return (
    <TouchableOpacity style={styles.button} onPress={onPress}>
      <Text style={styles.label}>{label}</Text>
    </TouchableOpacity>
  );
};

const styles = StyleSheet.create({
  button: {
    backgroundColor: 'blue',
    paddingVertical: 10,
    paddingHorizontal: 20,
    borderRadius: 5,
  },
  label: {
    color: 'white',
    fontWeight: 'bold',
  },
});

export default FormButton;

Este componente es una envoltura para el componente TouchableOpacity  de React Native. Se espera que se le proporcione un label y una función onPress que se ejecutará cuando se presione el botón.

Podemos también incluir checkbox en el formulario, para eso vamos crear un nuevo componente llamado FormCheckbox:

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

interface FormCheckboxProps {
  label: string;
  value: boolean;
  onValueChange: (newValue: boolean) => void;
}

const FormCheckbox: React.FC<FormCheckboxProps> = ({
  label,
  value,
  onValueChange,
}) => {
  const handlePress = () => {
    onValueChange(!value);
  };

  return (
    <TouchableOpacity style={styles.container} onPress={handlePress}>
      <View style={styles.checkbox}>
        {value && <View style={styles.checked} />}
      </View>
      <Text>{label}</Text>
    </TouchableOpacity>
  );
};

const styles = StyleSheet.create({
  container: {
    flexDirection: 'row',
    alignItems: 'center',
  },
  checkbox: {
    width: 20,
    height: 20,
    borderRadius: 4,
    borderWidth: 1,
    borderColor: '#ccc',
    marginRight: 10,
    alignItems: 'center',
    justifyContent: 'center',
  },
  checked: {
    width: 12,
    height: 12,
    borderRadius: 2,
    backgroundColor: '#333',
  },
});

export default FormCheckbox;

Este componente renderiza un checkbox con una etiqueta. El checkbox cambia de estado cuando se toca y llama a la función onValueChange proporcionada con el nuevo valor.

Para incluir un campo de contraseña en el formulario, podemos crear un nuevo componente llamado FormPasswordInput y usarlo en nuestro componente Form. Aquí mostramos un ejemplo:

import React, { useState } from 'react';
import { View, Text, TextInput, StyleSheet } from 'react-native';

interface FormPasswordInputProps {
  value: string;
  placeholder: string;
  onChangeText: (value: string) => void;
}

const FormPasswordInput: React.FC<FormPasswordInputProps> = ({
  value,
  placeholder,
  onChangeText,
}) => {
  const [showPassword, setShowPassword] = useState(false);

  const toggleShowPassword = () => {
    setShowPassword(!showPassword);
  };

  return (
    <View style={styles.container}>
      <TextInput
        style={styles.input}
        value={value}
        placeholder={placeholder}
        secureTextEntry={!showPassword}
        onChangeText={onChangeText}
      />
      <Text style={styles.toggle} onPress={toggleShowPassword}>
        {showPassword ? 'Ocultar' : 'Mostrar'}
      </Text>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flexDirection: 'row',
    alignItems: 'center',
  },
  input: {
    flex: 1,
    height: 40,
    borderColor: '#ccc',
    borderWidth: 1,
    borderRadius: 4,
    paddingHorizontal: 10,
  },
  toggle: {
    marginLeft: 10,
    color: '#666',
  },
});

export default FormPasswordInput;

Este componente renderiza un campo de contraseña que puede ocultarse o mostrarse presionando un botón. El valor del campo se almacena en el estado local del componente y se pasa a la función onChangeText  proporcionada cuando el usuario escribe en el campo.

Hooks de formulario

Ahora que hemos definido los componentes básicos, podemos empezar a construir los hooks que utilizaremos para manejar el estado del formulario. Crearemos un archivo useForm.ts en el que definiremos el hook useForm:

import { useState } from 'react';

interface FormFields {
  [fieldName: string]: string;
}

interface FormErrors {
  [fieldName: string]: string;
}

interface UseFormReturn {
  fields: FormFields;
  errors: FormErrors;
  setFieldValue: (fieldName: string, value: string) => void;
  handleSubmit: () => void;
}

const useForm = (onSubmit: (fields: FormFields) => void): UseFormReturn => {
  const [fields, setFields] = useState<FormFields>({});
  const [errors, setErrors] = useState<FormErrors>({});

  const setFieldValue = (fieldName: string, value: string) => {
    setFields((prevFields) => ({
      ...prevFields,
      [fieldName]: value,
    }));
  };

  const handleSubmit = () => {
    const formErrors: FormErrors = {};

    // Aquí realizamos las validaciones de cada campo
    // Si un campo es inválido, lo agregamos al objeto `formErrors`

    setErrors(formErrors);

    if (Object.keys(formErrors).length === 0) {
      onSubmit(fields);
    }
  };

  return {
    fields,
    errors,
    setFieldValue,
    handleSubmit,
  };
};

export default useForm;

Este hook devuelve cuatro propiedades:

  • fields: un objeto que contiene los valores actuales de los campos del formulario.
  • errors: un objeto que contiene los errores actuales de los campos del formulario.
  • setFieldValue: una función que se utiliza para establecer el valor de un campo del formulario.
  • handleSubmit: una función que se utiliza para manejar el envío del formulario.

El hook utiliza el estado de React para mantener el estado actual del formulario. También se encarga de realizar las validaciones de los campos del formulario y de llamar a la función onSubmit  proporcionada cuando el formulario es válido.

Componente de formulario completo

Ahora que hemos definido los componentes básicos y los hooks necesarios, podemos crear nuestro componente de formulario completo. Crearemos un archivo Form.tsx en el que definiremos el componente Form:

import React from 'react';
import { View, StyleSheet, Text } from 'react-native';
import FormButton from './FormButton';
import FormCheckbox from './FormCheckbox';
import FormInput from './FormInput';
import FormPasswordInput from './FormPasswordInput';
import useForm from './useForm';

interface FormProps {
  onSubmit: (fields: { [fieldName: string]: string | boolean | Date }) => void;
}

const Form: React.FC<FormProps> = ({ onSubmit }) => {
  const { fields, errors, setFieldValue, handleSubmit } = useForm(onSubmit);

  return (
    <View style={styles.container}>
      <FormInput
        value={fields.name || ''}
        placeholder="Nombre"
        onChangeText={(value) => setFieldValue('name', value)}
      />
      {errors.name && <Text style={styles.error}>{errors.name}</Text>}
      <FormInput
        value={fields.email || ''}
        placeholder="Correo electrónico"
        onChangeText={(value) => setFieldValue('email', value)}
      />
      {errors.email && <Text style={styles.error}>{errors.email}</Text>}
      <FormPasswordInput
        value={fields.password || ''}
        placeholder="Contraseña"
        onChangeText={(value) => setFieldValue('password', value)}
      />
      {errors.password && <Text style={styles.error}>{errors.password}</Text>}
      <FormCheckbox
        label="Acepto los términos y condiciones"
        value={fields.acceptTerms || false}
        onValueChange={(value) => setFieldValue('acceptTerms', value)}
      />
      {errors.acceptTerms && (
        <Text style={styles.error}>{errors.acceptTerms}</Text>
      )}
      <FormButton label="Enviar" onPress={handleSubmit} />
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    paddingHorizontal: 10,
  },
  error: {
    color: 'red',
  },
});

export default Form;

Este componente utiliza los componentes FormInputFormButton, FormCheckbox,... que definimos anteriormente, así como el hook useForm para manejar el estado del formulario. El componente renderiza dos campos de entrada de texto para el nombre y el correo electrónico, otro para la contraseña y un botón de envío. También renderiza cualquier error que pueda haber ocurrido en los campos del formulario.



ARTÍCULOS RELACIONADOS