Tutorial React: Construye una Aplicación de Notas con Firebase Autenticación y Base de Datos en Tiempo Real
Introducción
¡Hola desarrolladores! Si estás buscando un tutorial React práctico para crear una aplicación de notas que incluya funcionalidades esenciales como autenticación y base de datos en tiempo real, ¡estás en el lugar correcto!
En este tutorial detallado, vamos a construir paso a paso una aplicación de notas usando React para el frontend y Firebase como backend serverless para autenticación de usuarios y manejo de datos en tiempo real.
¿Qué aprenderás?
- Configurar un proyecto React moderno
- Integrar Firebase para autenticación y base de datos en tiempo real
- Implementar operaciones CRUD (Crear, Leer, Actualizar, Eliminar) para notas
- Desplegar tu aplicación para que el mundo pueda usarla
Este tutorial es ideal para desarrolladores principiantes e intermedios que quieren fortalecer sus habilidades en desarrollo frontend y backend serverless.
1. Configuración Inicial del Proyecto React
Primero, crearemos nuestro proyecto React usando create-react-app
. Si no tienes Node.js instalado, ve a nodejs.org para instalarlo.
Paso 1.1: Crear la aplicación React
Abre tu terminal y ejecuta:
1 2 3 4 |
npx create-react-app react-notes-app cd react-notes-app npm start |
Esto lanzará tu aplicación React en http://localhost:3000/
y podrás ver una página básica de bienvenida.
Paso 1.2: Instalar dependencias necesarias
Vamos a instalar Firebase para integrar autenticación y base de datos:
1 2 |
npm install firebase |
Además, instalaremos React Router para navegación entre páginas:
1 2 |
npm install react-router-dom |
Así tendremos todo listo para avanzar.
2. Configuración de Firebase
Paso 2.1: Crear un proyecto en Firebase
- Ve a Firebase Console.
- Crea un nuevo proyecto llamado “React Notes App”.
- Dentro del proyecto, ve a la sección “Authentication” y habilita el método “Email/Password”.
- Luego ve a “Realtime Database” y crea una base de datos en modo de prueba (para desarrollo) en la ubicación que prefieras.
Paso 2.2: Configurar Firebase en el proyecto React
Dentro de Firebase Console, accede a la sección de configuración del proyecto y obtén las credenciales:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
// src/firebaseConfig.js import { initializeApp } from 'firebase/app'; import { getAuth } from 'firebase/auth'; import { getDatabase } from 'firebase/database'; // Tu configuración de Firebase personalizada const firebaseConfig = { apiKey: "TU_API_KEY", authDomain: "TU_AUTH_DOMAIN", databaseURL: "TU_DATABASE_URL", projectId: "TU_PROJECT_ID", storageBucket: "TU_STORAGE_BUCKET", messagingSenderId: "TU_MESSAGING_SENDER_ID", appId: "TU_APP_ID" }; // Inicializa Firebase const app = initializeApp(firebaseConfig); // Exporta autenticación y base de datos export const auth = getAuth(app); export const database = getDatabase(app); |
Reemplaza las claves con las que te dio Firebase.
3. Implementar Autenticación de Usuarios con Firebase
Para que cada usuario tenga sus propias notas, necesitamos autenticar a los usuarios.
Paso 3.1: Crear componentes de registro e inicio de sesión
Vamos a crear dos componentes básicos: SignUp
y Login
.
SignUp.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
import React, { useState } from 'react'; import { auth } from './firebaseConfig'; import { createUserWithEmailAndPassword } from 'firebase/auth'; const SignUp = () => { const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [error, setError] = useState(null); const handleSignUp = async (e) => { e.preventDefault(); setError(null); try { await createUserWithEmailAndPassword(auth, email, password); alert('¡Usuario registrado exitosamente!'); } catch (err) { setError(err.message); } }; return ( <form onSubmit={handleSignUp}> <h2>Registrarse</h2> <input type="email" value={email} placeholder="Correo electrónico" onChange={(e) => setEmail(e.target.value)} required /> <input type="password" value={password} placeholder="Contraseña" onChange={(e) => setPassword(e.target.value)} required /> <button type="submit">Registrar</button> {error && <p style={{ color: 'red' }}>{error}</p>} </form> ); }; export default SignUp; |
Login.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
import React, { useState } from 'react'; import { auth } from './firebaseConfig'; import { signInWithEmailAndPassword } from 'firebase/auth'; const Login = () => { const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [error, setError] = useState(null); const handleLogin = async (e) => { e.preventDefault(); setError(null); try { await signInWithEmailAndPassword(auth, email, password); alert('¡Inicio de sesión exitoso!'); } catch (err) { setError(err.message); } }; return ( <form onSubmit={handleLogin}> <h2>Iniciar Sesión</h2> <input type="email" value={email} placeholder="Correo electrónico" onChange={(e) => setEmail(e.target.value)} required /> <input type="password" value={password} placeholder="Contraseña" onChange={(e) => setPassword(e.target.value)} required /> <button type="submit">Entrar</button> {error && <p style={{ color: 'red' }}>{error}</p>} </form> ); }; export default Login; |
Paso 3.2: Manejar el estado de autenticación
Para saber si un usuario está autenticado y obtener su información, usamos un hook que observe los cambios de autenticación:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
// src/App.js import React, { useEffect, useState } from 'react'; import { auth } from './firebaseConfig'; import { onAuthStateChanged, signOut } from 'firebase/auth'; import SignUp from './SignUp'; import Login from './Login'; import Notes from './Notes'; // Aquí irá nuestra app de notas function App() { const [user, setUser] = useState(null); useEffect(() => { const unsubscribe = onAuthStateChanged(auth, (currentUser) => { setUser(currentUser); }); return () => unsubscribe(); }, []); return ( <div className="App"> {user ? ( <> <button onClick={() => signOut(auth)}>Cerrar Sesión</button> <Notes user={user} /> </> ) : ( <> <Login /> <hr /> <SignUp /> </> )} </div> ); } export default App; |
Ahora el usuario puede registrarse, iniciar sesión y cerrar sesión.
4. Operaciones CRUD para Notas con Firebase Realtime Database
Vamos a implementar el componente principal Notes
para gestionar las notas del usuario autenticado.
Paso 4.1: Crear el componente Notes
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
import React, { useEffect, useState } from 'react'; import { ref, push, onValue, remove, update } from 'firebase/database'; import { database } from './firebaseConfig'; const Notes = ({ user }) => { const [notes, setNotes] = useState({}); const [newNote, setNewNote] = useState(''); const notesRef = ref(database, `notes/${user.uid}`); // Notas por usuario // Cargar todas las notas en tiempo real useEffect(() => { const unsubscribe = onValue(notesRef, (snapshot) => { const data = snapshot.val() || {}; setNotes(data); }); return () => unsubscribe(); }, [user.uid]); // Crear una nueva nota const addNote = () => { if (newNote.trim() === '') return; // No permitir notas vacías const noteRef = push(notesRef); noteRef.set({ text: newNote.trim() }); setNewNote(''); }; // Eliminar nota por ID const deleteNote = (id) => { const noteToRemove = ref(database, `notes/${user.uid}/${id}`); remove(noteToRemove); }; // Actualizar nota por ID const updateNote = (id, text) => { const noteToUpdate = ref(database, `notes/${user.uid}/${id}`); update(noteToUpdate, { text }); }; return ( <div> <h2>Mis Notas</h2> <input type="text" value={newNote} placeholder="Nueva nota" onChange={(e) => setNewNote(e.target.value)} /> <button onClick={addNote}>Agregar Nota</button> <ul> {Object.entries(notes).map(([id, note]) => ( <NoteItem key={id} id={id} note={note} onDelete={deleteNote} onUpdate={updateNote} /> ))} </ul> </div> ); }; // Componente para cada nota individual con edición const NoteItem = ({ id, note, onDelete, onUpdate }) => { const [isEditing, setIsEditing] = useState(false); const [text, setText] = useState(note.text); const handleSave = () => { onUpdate(id, text.trim()); setIsEditing(false); }; return ( <li> {isEditing ? ( <> <input type="text" value={text} onChange={(e) => setText(e.target.value)} /> <button onClick={handleSave}>Guardar</button> <button onClick={() => setIsEditing(false)}>Cancelar</button> </> ) : ( <> <span>{note.text}</span> <button onClick={() => setIsEditing(true)}>Editar</button> <button onClick={() => onDelete(id)}>Eliminar</button> </> )} </li> ); }; export default Notes; |
5. Estructurar la Navegación con React Router (Opcional)
Si prefieres una app con rutas para login y notas más separadas, puedes usar React Router.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
// src/App.js import React, { useEffect, useState } from 'react'; import { auth, } from './firebaseConfig'; import { onAuthStateChanged, signOut } from 'firebase/auth'; import { BrowserRouter as Router, Route, Routes, Navigate } from 'react-router-dom'; import Login from './Login'; import SignUp from './SignUp'; import Notes from './Notes'; function App() { const [user, setUser] = useState(null); useEffect(() => { const unsubscribe = onAuthStateChanged(auth, setUser); return () => unsubscribe(); }, []); return ( <Router> <Routes> <Route path="/" element={user ? <Notes user={user} /> : <Navigate to="/login" />} /> <Route path="/login" element={!user ? <Login /> : <Navigate to="/" />} /> <Route path="/signup" element={!user ? <SignUp /> : <Navigate to="/" />} /> </Routes> {user && <button onClick={() => signOut(auth)}>Cerrar Sesión</button>} </Router> ); } export default App; |
Con esto, tienes un control claro sobre las rutas y la navegación.
6. Despliegue Básico de la Aplicación
Para que otros puedan usar tu aplicación de notas, puedes desplegarla rápidamente.
Paso 6.1: Construir producción
1 2 |
npm run build |
Paso 6.2: Despliegue con Firebase Hosting
- Instala CLI de Firebase
1 2 |
npm install -g firebase-tools |
- Inicia sesión en Firebase en la terminal
1 2 |
firebase login |
- Inicializa el hosting (selecciona el proyecto creado previamente)
1 2 |
firebase init |
Configura la carpeta de build
como directorio público y configura como SPA si se usa React Router.
- Despliega
1 2 |
firebase deploy |
¡Listo! Ahora tienes una app de notas con React y Firebase accesible en la web.
Buenas Prácticas en el Desarrollo
- Validaciones: Siempre valida entradas del usuario para evitar errores y ataques.
- Manejo de errores: Captura y muestra errores de forma amigable.
- Seguridad de Firebase: Configura reglas específicas en Realtime Database para proteger datos por usuario.
- Componentización: Divide el código en componentes reutilizables y claros.
- Control de estado: Usa hooks como
useState
yuseEffect
para mantener la app reactiva. - Documenta tu código: Esto facilita mantenimiento y aprendizaje.
Conclusión
¡Felicidades! Has creado una aplicación de notas funcional utilizando React y Firebase que incluye autenticación, operaciones CRUD en tiempo real y un flujo sencillo para usuarios.
Este proyecto es una excelente base para profundizar en desarrollo frontend moderno y backend serverless con Firebase.
¿Qué sigue?
- Mejora la UI con frameworks como Tailwind CSS o Material UI.
- Agrega funcionalidades como etiquetas o búsqueda de notas.
- Implementa notificaciones o sincronización avanzada.
Si te gustó este tutorial, comparte con otros desarrolladores y ¡comienza a construir tus propias aplicaciones React + Firebase hoy mismo!
¡Manos a la obra y feliz codificación! 🚀