Cover photo

App móvil con CRUD conectado a servidor LAMP

Objetivo general

Desarrollar una app móvil en React Native (Expo) capaz de conectarse a una API PHP que realiza operaciones CRUD sobre una tabla en MySQL, todo dentro de una red local.

Herramientas necesarias

  • MySQ: Base de datos

  • PHP (Apache o XAMPP): API en backend

  • React Native + ExpoApp: móvil frontend

  • Postman (opcional): Prueba de endpoints API

  • VS Code: Editor de código

  • Expo Go: Pruebas en el móvil (iOS/Android)

Parte 1: Crear la base de datos

  1. En phpMyAdmin o línea de comandos de MySQL:

CREATE DATABASE tienda;

USE tienda;

CREATE TABLE productos (
  id INT AUTO_INCREMENT PRIMARY KEY,
  nombre VARCHAR(100),
  precio DECIMAL(10,2)
);

Parte 2: Crear la API en PHP

Estructura del backend (ubicado en /htdocs/api)

api/
├── conexion.php
├── obtener.php
├── crear.php
├── actualizar.php
├── eliminar.php

fichero conexion.php

<?php
$host = "localhost";
$user = "root";
$password = ""; // tu contraseña
$db = "tienda";

$conn = new mysqli($host, $user, $password, $db);

if ($conn->connect_error) {
    die("Conexión fallida: " . $conn->connect_error);
}
?>

Fichero obtener.php

<?php
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json");
include "conexion.php";

$sql = "SELECT * FROM productos";
$result = $conn->query($sql);

$datos = [];

while ($fila = $result->fetch_assoc()) {
    $datos[] = $fila;
}

echo json_encode($datos);
?>

fichero crear.php

<?php
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json");
include "conexion.php";

$input = json_decode(file_get_contents("php://input"), true);

$nombre = $input["nombre"];
$precio = $input["precio"];

$sql = "INSERT INTO productos (nombre, precio) VALUES ('$nombre', '$precio')";

if ($conn->query($sql)) {
    echo json_encode(["mensaje" => "Producto creado"]);
} else {
    echo json_encode(["mensaje" => "Error"]);
}
?>

fichero actualizar.php

<?php
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json");
include "conexion.php";

$input = json_decode(file_get_contents("php://input"), true);

$id = $input["id"];
$nombre = $input["nombre"];
$precio = $input["precio"];

$sql = "UPDATE productos SET nombre='$nombre', precio='$precio' WHERE id=$id";

if ($conn->query($sql)) {
    echo json_encode(["mensaje" => "Producto actualizado"]);
} else {
    echo json_encode(["mensaje" => "Error"]);
}
?>

fichero eliminar.php

<?php
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json");
include "conexion.php";

$input = json_decode(file_get_contents("php://input"), true);
$id = $input["id"];

$sql = "DELETE FROM productos WHERE id=$id";

if ($conn->query($sql)) {
    echo json_encode(["mensaje" => "Producto eliminado"]);
} else {
    echo json_encode(["mensaje" => "Error"]);
}
?>

Parte 3: Crear app en React Native con Expo

  • Crear proyecto:

npx create-expo-app tiendaApp --template -blank
cd tiendaApp
npx expo start
  • Instala dependencias (opcional si usarás formularios o navegación):

npm install react-native-paper
  • Lectura + Formulario básico (App.js

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

export default function App() {
  const [productos, setProductos] = useState([]);
  const [nombre, setNombre] = useState("");
  const [precio, setPrecio] = useState("");

  const API = "http://<TU_IP_LOCAL>/api";

  const obtenerDatos = () => {
    fetch(`${API}/obtener.php`)
      .then(res => res.json())
      .then(data => setProductos(data))
      .catch(err => console.error(err));
  };

  const crearProducto = () => {
    fetch(`${API}/crear.php`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ nombre, precio })
    })
      .then(res => res.json())
      .then(() => {
        obtenerDatos();
        setNombre("");
        setPrecio("");
      });
  };

  const eliminarProducto = (id) => {
    fetch(`${API}/eliminar.php`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ id })
    })
      .then(res => res.json())
      .then(() => obtenerDatos());
  };

  useEffect(() => {
    obtenerDatos();
  }, []);

  return (
    <View style={styles.container}>
      <Text style={styles.title}>Tienda</Text>

      <FlatList
        data={productos}
        keyExtractor={item => item.id.toString()}
        renderItem={({ item }) => (
          <View style={styles.item}>
            <Text>{item.nombre} - ${item.precio}</Text>
            <Button title="Eliminar" onPress={() => eliminarProducto(item.id)} />
          </View>
        )}
      />

      <TextInput placeholder="Nombre" value={nombre} onChangeText={setNombre} style={styles.input} />
      <TextInput placeholder="Precio" value={precio} onChangeText={setPrecio} keyboardType="numeric" style={styles.input} />
      <Button title="Crear producto" onPress={crearProducto} />
    </View>
  );
}

const styles = StyleSheet.create({
  container: { padding: 20, marginTop: 40 },
  title: { fontSize: 24, fontWeight: 'bold', marginBottom: 10 },
  input: { borderWidth: 1, marginVertical: 5, padding: 8 },
  item: { marginBottom: 10 }
});

Continua en:

https://www.frexus.dev/post/como-se-conectan-las-apps-moviles-a-servidores-y-bases-de-datos-fundamentos-esenciales/