Original article: How to Build a Calculator App Using React Native – A Step-by-Step Tutorial

Una aplicación de calculadora es una aplicación simple que siempre está disponible en todos los dispositivos Android, iOS y de escritorio.

En este artículo, crearemos una aplicación de calculadora utilizando React Native y Expo. Entonces, ¿por qué estamos usando estas herramientas?

React Native es un marco basado en JavaScript que se puede usar para desarrollar aplicaciones móviles en dos sistemas operativos al mismo tiempo: Android e iOS. React Native fue lanzado por primera vez en 2015 por Facebook y es de código abierto.

Puedes encontrar más información sobre React Native aquí.

Expo es un conjunto de herramientas, bibliotecas y servicios que puede usar para simplificar su código React Native. Entonces puede ejecutar aplicaciones React Native en el emulador Expo.

Puedes encontrar más información sobre Expo aquí.

Antes de comenzar a crear una aplicación de calculadora, primero deberás instalar Node.js, React Native y Expo en tu ordenador.

Requisitos previos

  1. Instala Node.js: Puedes ver cómo instalarlo aquí.
  2. Instala React Native: Puedes ver la documentación de instalación aquí.
  3. Instala Expo: Puedes ver la documentación de instalación aquí.

Paso 1: Crear un nuevo proyecto

El primer paso es crear un nuevo proyecto. Usa Expo CLI para crear la base de código React Native con el siguiente comando:

$ expo init calculator-app

Entonces tendrás la opción de iniciar el proyecto que desees. Aquí elegimos la opción en blanco y usamos JavaScript como se muestra a continuación:

image-349
choose template expo project

Después de eso, el proceso continuará descargando todas las dependencias.

Paso 2: Crear el componente de botón

Cuando desarrolles aplicaciones con React Native, asegúrate de dividir los componentes de la interfaz de usuario en componentes más pequeños para que el código que crees se pueda reutilizar.

Primero, crea una nueva carpeta llamada "componentes" para almacenar el código de tu componente. El primer componente que crearemos es un botón, así que crea un nuevo archivo llamado Button.js. Aquí está el código fuente para el componente Botón:

import { Dimensions, StyleSheet, Text, TouchableOpacity } from "react-native";

export default ({ onPress, text, size, theme }) => {
  const buttonStyles = [styles.button];
  const textStyles = [styles.text];

  if (size === "double") {
    buttonStyles.push(styles.buttonDouble);
  }

  if (theme === "secondary") {
    buttonStyles.push(styles.buttonSecondary);
    textStyles.push(styles.textSecondary);
  } else if (theme === "accent") {
    buttonStyles.push(styles.buttonAccent);
  }

  return (
    <TouchableOpacity onPress={onPress} style={buttonStyles}>
      <Text style={textStyles}>{text}</Text>
    </TouchableOpacity>
  );
};

Explicación del código:

  • En la línea 3, hay cuatro propiedades que necesitamos para hacer este componente Botón: onPress, texto, tamaño y tema.
  • Cada una de las propiedades tiene una función como onPress para manejar acciones en los botones.
  • El componente de botón que creamos tiene 2 tipos de temas, secundarios y de acento, y 1 tamaño, doble.
  • El componente de botón usa el componente React Native predeterminado, TouchableOpacity.

Después de crear el código del componente, no olvides agregar el estilo para este componente de botón. Aquí está el código para el estilo del componente:

// set dimmenstion
const screen = Dimensions.get("window");
const buttonWidth = screen.width / 4;

const styles = StyleSheet.create({
  button: {
    backgroundColor: "#333333",
    flex: 1,
    height: Math.floor(buttonWidth - 10),
    alignItems: "center",
    justifyContent: "center",
    borderRadius: Math.floor(buttonWidth),
    margin: 5,
  },
  text: {
    color: "#fff",
    fontSize: 24,
  },
  textSecondary: {
    color: "#060606",
  },
  buttonDouble: {
    width: screen.width / 2 - 10,
    flex: 0,
    alignItems: "flex-start",
    paddingLeft: 40,
  },
  buttonSecondary: {
    backgroundColor: "#a6a6a6",
  },
  buttonAccent: {
    backgroundColor: "#ffc107",
  },
});

Entonces, el código completo de nuestro componente de botón es el siguiente:

import { Dimensions, StyleSheet, Text, TouchableOpacity } from "react-native";

export default ({ onPress, text, size, theme }) => {
  const buttonStyles = [styles.button];
  const textStyles = [styles.text];

  if (size === "double") {
    buttonStyles.push(styles.buttonDouble);
  }

  if (theme === "secondary") {
    buttonStyles.push(styles.buttonSecondary);
    textStyles.push(styles.textSecondary);
  } else if (theme === "accent") {
    buttonStyles.push(styles.buttonAccent);
  }

  return (
    <TouchableOpacity onPress={onPress} style={buttonStyles}>
      <Text style={textStyles}>{text}</Text>
    </TouchableOpacity>
  );
};

// set dimmenstion
const screen = Dimensions.get("window");
const buttonWidth = screen.width / 4;

const styles = StyleSheet.create({
  button: {
    backgroundColor: "#333333",
    flex: 1,
    height: Math.floor(buttonWidth - 10),
    alignItems: "center",
    justifyContent: "center",
    borderRadius: Math.floor(buttonWidth),
    margin: 5,
  },
  text: {
    color: "#fff",
    fontSize: 24,
  },
  textSecondary: {
    color: "#060606",
  },
  buttonDouble: {
    width: screen.width / 2 - 10,
    flex: 0,
    alignItems: "flex-start",
    paddingLeft: 40,
  },
  buttonSecondary: {
    backgroundColor: "#a6a6a6",
  },
  buttonAccent: {
    backgroundColor: "#ffc107",
  },
});

Paso 3: Crear el componente de fila

El siguiente componente que crearemos es un componente Fila. Este componente es útil para crear filas cuando queremos procesar diseños.

Aquí está el código para el componente Fila y su código de estilo:

import { StyleSheet, View } from "react-native";

const Row = ({ children }) => {
  return <View style={styles.container}>{children}</View>;
};

// create styles of Row
const styles = StyleSheet.create({
  container: {
    flexDirection: "row",
  },
});

export default Row;

Esto es lo que está pasando:

  • En el componente de fila, hay 1 propiedad que necesitamos: Niños.
  • El componente de fila usa el componente de vista predeterminado de React Native.
  • flexDirection: "fila" en este estilo se usa para hacer que el diseño sea una fila.

Paso 4: Crear la lógica de la calculadora

Crea una nueva carpeta llamada útil y un nuevo archivo calculator.js . Aquí crearemos una función lógica en la aplicación de calculadora que implementaremos más adelante en el archivo App.js. Aquí está el código completo:

export const initialState = {
  currentValue: "0",
  operator: null,
  previousValue: null,
};

export const handleNumber = (value, state) => {
  if (state.currentValue === "0") {
    return { currentValue: `${value}` };
  }

  return {
    currentValue: `${state.currentValue}${value}`,
  };
};

const handleEqual = (state) => {
  const { currentValue, previousValue, operator } = state;

  const current = parseFloat(currentValue);
  const previous = parseFloat(previousValue);
  const resetState = { operator: null, previousValue: null };

  switch (operator) {
    case "+":
      return {
        currentValue: `${previous + current}`,
        ...resetState,
      };
    case "-":
      return {
        currentValue: `${previous - current}`,
        ...resetState,
      };
    case "*":
      return {
        currentValue: `${previous * current}`,
        ...resetState,
      };
    case "/":
      return {
        currentValue: `${previous / current}`,
        ...resetState,
      };

    default:
      return state;
  }
};

// calculator function
const calculator = (type, value, state) => {
  switch (type) {
    case "number":
      return handleNumber(value, state);
    case "clear":
      return initialState;
    case "posneg":
      return {
        currentValue: `${parseFloat(state.currentValue) * -1}`,
      };
    case "percentage":
      return {
        currentValue: `${parseFloat(state.currentValue) * 0.01}`,
      };
    case "operator":
      return {
        operator: value,
        previousValue: state.currentValue,
        currentValue: "0",
      };
    case "equal":
      return handleEqual(state);
    default:
      return state;
  }
};

export default calculator;

Y esto es lo que está pasando:

  • initialState se usa para dar el valor predeterminado a nuestra aplicación de calculadora.
  • La función handleNumber sirve para devolver el valor de la calculadora y tiene 2 propiedades: valor y estado.
  • El identificador de función Equal sirve para procesar el valor establecido de cada operador matemático y devuelve su valor.
  • La calculadora de funciones válida cada operador dado. Por ejemplo, si el número llama a la función handleNumber, si está claro, devolverá el valor de estado predeterminado de initiaState, y así sucesivamente.

Paso 5: Refactorizar el archivo App.js

Una vez que hemos creado todos los componentes y el proceso lógico, el siguiente paso es realizar ajustes en el código del archivo App.js. Aquí está el código completo:

import React, { Component } from "react";
import { SafeAreaView, StyleSheet, Text, View } from "react-native";
import Button from "./components/Button";
import Row from "./components/Row";
import calculator, { initialState } from "./util/calculator";

// create class component of App
export default class App extends Component {
  state = initialState;

  // handle tap method
  HandleTap = (type, value) => {
    this.setState((state) => calculator(type, value, state));
  };

  // render method
  render() {
    return (
      <View style={styles.container}>
        {/* Status bae here */}
        <SafeAreaView>
          <Text style={styles.value}>
            {parseFloat(this.state.currentValue).toLocaleString()}
          </Text>

          {/* Do create componentRow */}
          <Row>
            <Button
              text="C"
              theme="secondary"
              onPress={() => this.HandleTap("clear")}
            />

            <Button
              text="+/-"
              theme="secondary"
              onPress={() => this.HandleTap("posneg")}
            />

            <Button
              text="%"
              theme="secondary"
              onPress={() => this.HandleTap("percentage")}
            />

            <Button
              text="/"
              theme="accent"
              onPress={() => this.HandleTap("operator", "/")}
            />
          </Row>

          {/* Number */}
          <Row>
            <Button text="7" onPress={() => this.HandleTap("number", 7)} />
            <Button text="8" onPress={() => this.HandleTap("number", 8)} />
            <Button text="9" onPress={() => this.HandleTap("number", 9)} />
            <Button
              text="X"
              theme="accent"
              onPress={() => this.HandleTap("operator", "*")}
            />
          </Row>

          <Row>
            <Button text="5" onPress={() => this.HandleTap("number", 5)} />
            <Button text="6" onPress={() => this.HandleTap("number", 6)} />
            <Button text="7" onPress={() => this.HandleTap("number", 7)} />
            <Button
              text="-"
              theme="accent"
              onPress={() => this.HandleTap("operator", "-")}
            />
          </Row>

          <Row>
            <Button text="1" onPress={() => this.HandleTap("number", 1)} />
            <Button text="2" onPress={() => this.HandleTap("number", 2)} />
            <Button text="3" onPress={() => this.HandleTap("number", 3)} />
            <Button
              text="+"
              theme="accent"
              onPress={() => this.HandleTap("operator", "+")}
            />
          </Row>

          <Row>
            <Button text="0" onPress={() => this.HandleTap("number", 0)} />
            <Button text="." onPress={() => this.HandleTap("number", ".")} />
            <Button
              text="="
              theme="primary"
              onPress={() => this.HandleTap("equal", "=")}
            />
          </Row>
        </SafeAreaView>
      </View>
    );
  }
}

// create styles of app
const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#202020",
    justifyContent: "flex-end",
  },
  value: {
    color: "#fff",
    fontSize: 42,
    textAlign: "right",
    marginRight: 20,
    marginBottom: 10,
  },
});

Algunas notas rápidas:

  • handleTap es una función que creamos que tiene como objetivo proporcionar valores de estado y llamar a utils/calculator.
  • Aquí llamamos a dos componentes, Botón y Fila, para diseñar la apariencia de la calculadora, como sus números, operaciones matemáticas y el proceso de cálculo.

Paso 6: Ejecuta la aplicación

En este paso intentaremos ejecutar la aplicación de calculadora en el dispositivo o podemos usar un emulador. Aquí uso el simulador de iPhone de MacOS. Ejecuta el siguiente comando para ejecutar el programa:

$ yarn ios

El proceso en ejecución aquí usa Expo como se muestra a continuación:

image-350

Si el proceso de compilación está completo, entonces la pantalla de la aplicación de calculadora que programamos será así:

image-351

Conclusión

Eso es suficiente para este artículo. Aprendiste sobre estilo, componentes, propiedades y estados en React Native y creaste una aplicación de calculadora funcional.

Si necesitas el código fuente completo, puedes visitar mi repositorio de GitHub aquí: https://github.com/bangadam/calculator-app

¡Gracias por leer!

¡Disponible para un nuevo proyecto! Hablemos.
Correo electrónico: bangadam.dev@gmail.com
Linkedin: https://www.linkedin.com/in/bangadam