¿Cómo programar una app en react native y redux para registrar usuarios a través de un api rest parte 1?


1.- Introducción

Ya creamos un api rest para registrar un usuario, iniciar sesión para obtener un jsonwebtoken y actualizar el perfil de usuario. Ahora vamos a crear una aplicación en react native con redux y react-navigation para hacer uso de esta api rest.

2.- Instalación

Necesitamos instalar el generador de react native que puedes revisar la documentación en  el siguiente enlace y para crear nuestra app usamos el siguiente comando:

create-react-native-app herelodin.com

Ahora vamos a la carpeta que acaba de generar react native con el comando

cd herelodin.com

debemos inizializar nuestra aplicación utilizamos el comando

react-native eject

que se encargara que crear la carpeta ios y android para cada plataforma por el momento vamos a utilizar redux para almacenar toda la información en la aplicación y react-navigation para transiciones utilizamos el siguiente comando para instalar las dependencias.

yarn add react-redux redux  redux-logger redux-persist  redux-thunk react-navigation axios --save

3.- Estructura

Por experiencia debemos tener estructurados correctamente  nuestra aplicacion, definir componentes, screens, reducers y actions, despues de algunos años y de trabajo en equipo llegamos a la siguiente estructura como óptima.

  • src  carpeta que contiene toda la estructura de nuestra app
    • components aqui agregamos todos los componentes de nuestra app como botones, inputs, iconos etc…
    • config en esta carpeta podemos agregar todas las rutas para conectarnos a nuestra api  y los stylos de nuestros components
    • i18n si la app tuviera mas de 1 idioma aqui agregamos los archivos json para los idiomas correspondientes
    • redux
      • actions aqui colocamos todas nuestras acciones por ejemplo hacer una peticion para registrar un usuario
      • reducers en esta carpeta creamos la estructura de nuestros datos.
    • screens agregamos todas las pantalls de nuestra app por ejemplo la pantalla register que manda a llamar a los componentes para registrar un usuario
    • utils en esta carpeta creamos funciones que podemos utilizar en nuestro proyecto como por ejemplo validar un email y no tener que crear la funcion en cada lugar que se requiera.

4.- Comó configurar reducers

Vamos a crear nuestro primer reducers donde vamos almacenar los datos de usuario y el token de la sesión.

Para esto vamos a la carpeta redux/reducers y creamos el archivo session.js

import { SET_SESSION, CLEAR_SESION, SET_USER } from '../ActionTypes.js'
const session = (state = { }, action) => {
    switch (action.type) {
        case SET_USER : {
        const { user } = action
            return {
                ...state,
                user
            }
        }
        case CLEAR_SESION: {
            return { };
        }
        case SET_SESSION : {
            const { token, user } = action
            return {
                token,
                user
            }
        }
        default: {
              return state
        }
    }
}
export default session;

Donde vamos a importar de nuestro archivo ActionTypes.js las variables SET_SESSION, CLEAR_SESSION Y SET_USER que se encargaran de definir cada acción, ahora vamos a crear en la misma carpeta el archivo index que se encarga de combinar todos los reducers aunque en este caso solo tenemos uno https://github.com/herel/react-native-redux-registro-de-usuarios/blob/master/src/redux/reducers/index.js

import { combineReducers } from 'redux';
import session from './session';

const reducers = combineReducers({
  session
});

export default reducers;

Listo ya tenemos nuestro primer reducers, se que esto es algo complicado de entender pero si sigues estos pasos te bajas el repo y con algo de practica podras dominar redux.

5.- Comó configurar redux, persistStore, store y PersistGate.

Ahora  cada vez que inicie nuestra aplicación en react debemos cargar los datos que en ella se encuentran por ejemplo  los datos de usuario y la sesión, si es la primera vez que se abre la app debemos cargar los valores por default para esto debemos ir a nuestro archivo principal index.js y utilizar el siguiente codigo:

import React, { Component } from 'react'
import { AppRegistry } from 'react-native';
/*redux configuration*/
import { applyMiddleware, compose, createStore } from 'redux'
import { persistStore, persistReducer } from 'redux-persist'
import storage from 'redux-persist/lib/storage'
import { PersistGate } from 'redux-persist/integration/react'
import { Provider } from 'react-redux'
import { createLogger } from 'redux-logger'
import reducers from './src/redux/reducers'
import thunk from 'redux-thunk';
//app views and components
import App from './src';

const loggerMiddleware = createLogger({ predicate: () => false })
const persistedReducer = persistReducer({ key: 'root', storage, blacklist: ['filter', 'modals'] }, reducers)

function configureStore (initialState) {
  const enhancer = compose(
    applyMiddleware(thunk, loggerMiddleware)
  )
  return createStore(persistedReducer, initialState, enhancer)
}

const initialState = {}
export const store = configureStore(initialState)
export const persistor = persistStore(store)

export default class Herelodin extends Component {
    render () {
        return (
            <Provider store={store}>
                <PersistGate loading={null} persistor={persistor}>
                    <App />
                </PersistGate>
            </Provider>
        )
    }
}

AppRegistry.registerComponent('herelodin', () => Herelodin);

Ya implementamos redux en nuestra aplicación mientras la app carga los datos podemos mostrar algun splash en este caso deje el valor en null y una vez que redux carga los datos se inicializa nuestra app.

6.- Comó configurar StackNavigator

Ya tenemos configurado redux, con nuestro primer reduxcers y nuestro provider que se encargar de inyectar la data a nuestra app, ahora debemos definir las pantallas (screens) que vamos a utlizar por el momento solo vamos a mostrar el formulario de registro de usuarios para esto vamos al archivo src/index.js

import React, { Component } from 'react';
import { StackNavigator } from 'react-navigation';
import Form from './screens/Form.js';


const Navigation = StackNavigator({
    home : {
        screen : Form
    }
},{
    headerMode: 'none'
});

export default Navigation;

¡Genial! ya creamos el primer screen de nuestra App llamada home donde manda a llamar al componente Form que se encuentra dentro de la carpeta screens en este archivo vamos a importar el component Input que se encargara de mostrar los 4 inputs para nombre, apellidos, email y contraseña.

7. Como crear componentes en react native

Como comente en el punto anterior necesitamos crear la mayor parte de componentes para reutlizar en toda nuestra app y no tener que repetir el codigo para esto vamos a crear el component input en la siguiente ruta src/components/Input.js

import React, { Component } from 'react';
import { View, TextInput } from 'react-native';
import {
  InputContainer,
  InputStyle
} from '../config/styles';

class Input extends Component{
    render(){
        return (
            <View style={InputContainer}>
                <TextInput
                    placeholder={this.props.placeholder}
                    placeholderTextColor="rgba(255,255,255,0.3)"
                    style={InputStyle}
                    value={this.props.value}
                    keyboardType={this.props.keyboardType}
                    autoCapitalize='none'
                    underlineColorAndroid='transparent'
                    secureTextEntry={this.props.secureTextEntry}
                    onChangeText={this.props.onChangeText}
                    autoCorrect={false}
                />
            </View>
        )
    }

}

export default Input;

Como notaron en este componente importamos estilos por default que podemos reutilizar en otro componente el value del input viene de los props de igual forma si el valor del input cambiar se ejecuta la funcion onChague que tambien viene de los props como vemos no guardamos nigun dato en este componente ya que la idea es reutilizarlo en toda la app.

8.- Reutilizar componentes

Es muy importante reutilizar componentes para que nuestra app sea lo más óptima posible en este ejemplo tenemos 4 inputs pero no creamos  4 veces el mismo codigo, lo que hicimos fue crear un componente llamado input y asi  solo llamarlo en nuestro screen y pasarle los atributos para que se adapte para un campo de email, contraseña ó solo texto.

En nuestro archivo src/screens/form.js reutilizamos el componente así:

import React, { Component } from 'react';
import { View } from 'react-native';
import Input from '../components/Input';
import LinearGradient from 'react-native-linear-gradient';
import {
    container
} from '../config/styles';

class Form extends Component{

    constructor(props){
        super(props);
        this.state = {
            firstName : '',
            lastName  : '',
            email       : '',
            password  : '' 
        }
    }

    render(){
        return (
            <LinearGradient
                colors={['#441E35','#320622']}
                style={container}>
                <Input
                    placeholder="Nombre(s)"
                    onChangeText={(firstName) => this.setState({firstName})}
                    value={this.state.firstName}
                    />
                <Input
                    placeholder="Apellido(s)"
                    onChangeText={(lastName) => this.setState({lastName})}
                    value={this.state.lastName}
                    />
                <Input
                    placeholder="Apellido(s)"
                    onChangeText={(email) => this.setState({email})}
                    value={this.state.email}
                />
                <Input
                    secureTextEntry={true}
                    placeholder="Contraseña"
                    onChangeText={(password) => this.setState({password})}
                    value={this.state.password}
                />
            </LinearGradient>
        );
    }
}

export default Form;

Cada vez que el usuario ingrese su nombre, emai y contraseña se ejecuta la funcion onChangeText y asignamos el valor a nuestro state asi reutilizamos de forma correcta el componente.

8.1- Como validar campos en react native

Ahora debemos agregar un botón con el texto “Registrar” pero si el usuario no ha ingresado ningun dato este botón debe estar deshabilidado (disabled) para esto creamos un componente llamado Button.js

import React, { Component } from 'react';
import { View, TouchableHighlight , Text } from 'react-native';
import {
    button,
    button_text 
} from '../config/styles';
import {
    REDCOLOR
} from '../config/const';


class Button extends Component{

    onPress(){
        if(this.props.onPress)
            this.props.onPress();
    }

    _getBackground(){
        if(this.props.disabled)
            return { backgroundColor : 'rgba(255,255,255,0.5)' }
        return { backgroundColor : REDCOLOR };
    }

    render(){
        return (
            <TouchableHighlight
                activeOpacity={1}
                underlayColor="rgba(255,255,255,.6)"
                onPress={this.onPress.bind(this)}
                style={[button,this._getBackground()]}>
                <Text style={button_text}>{this.props.text}</Text>
            </TouchableHighlight>
        );
    }
}

export default Button;

Ahora importamos el boton en nuestro formulario y agregamos la funcion getDisabled que validara si los campos de nombre, email y contraseña son correctos.

import React, { Component } from 'react';
import { View } from 'react-native';
import Input from '../components/Input';
import Button from '../components/Button';
import LinearGradient from 'react-native-linear-gradient';
import {
    container
} from '../config/styles';

class Form extends Component{

    constructor(props){
        super(props);
        this.state = {
            firstName : '',
            lastName  : '',
            email       : '',
            password  : '' 
        }
    }

    _getDisabled(){
        let disabled = false;
        if(!this.state.firstName || this.state.firstName.length <=4)
            disabled = true;
        if(!this.state.lastName || this.state.lastName.length <=4)
            disabled = true;
        if(!this.state.email)
            disabled = true;
        if(!this.state.password || this.state.password.length <=5)
            disabled = true;

        return disabled;
    }
    render(){
        return (
            <LinearGradient
                colors={['#441E35','#320622']}
                style={container}>
                <Input
                    placeholder="Nombre(s)"
                    onChangeText={(firstName) => this.setState({firstName})}
                    value={this.state.firstName}
                    />
                <Input
                    placeholder="Apellido(s)"
                    onChangeText={(lastName) => this.setState({lastName})}
                    value={this.state.lastName}
                    />
                <Input
                    placeholder="Correo electrónico"
                    onChangeText={(email) => this.setState({email})}
                    value={this.state.email}
                />
                <Input
                    secureTextEntry={true}
                    placeholder="Contraseña"
                    onChangeText={(password) => this.setState({password})}
                    value={this.state.password}
                />
                <Button
                    disabled={this._getDisabled()}
                    text="Registrar"
                />
            </LinearGradient>
        );
    }
}

export default Form;

si ejecutamos nuestra app con el comando react-native run-ios obtenemos el siguiente resultado

Gracias por leer y comentar en el siguiente post vamos a implementar actions para enviar la información de la app a nuestra api, te dejo algunos lirbos que me ayudaron mucho para mejorar las buenas practicas a la hora de programar.