Autor: Juan Pablo Fuentes
CRUD sencillo
Vamos a hacer un CRUD para la siguiente ‘base de datos’
{ "notes": [ { "id": 1, "content": "HTML is easy", "date": "2023-01-03T10:30:11.414Z", "important": false }, { "id": 2, "content": "Browser can execute only JavaScript", "date": "2019-05-30T18:39:34.091Z", "important": false }, { "id": 3, "content": "GET and POST are the most important methods of HTTP protocol", "date": "2023-01-09T09:29:26.131Z", "important": true }, { "content": "Cchuetes", "date": "2022-12-18T20:25:10.598Z", "important": true, "id": 4 }, { "id": 5, "content": "Comprar pan", "date": "2023-01-09T08:46:37.794Z", "important": false }, { "content": "Nueva nota", "date": "2023-01-09T09:29:21.122Z", "important": false, "id": 6 } ] }
De momento solo gestionamos el contenido. La fecha la ponemos automáticamente y si es importante o no lo dejamos de lado, ponemos siempre ‘false’.
CRUD comentado
import React, { useState, useEffect } from 'react'; import axios from 'axios'; const App = () => { // Estado de los posts. Aquí cargaremos la información de la api // Parecido a la de tareas const [posts, setPosts] = useState([]); // Para el formulario, en este caso todos los campos dentro de un objeto const [nuevoPost, setNuevoPost] = useState({ title: '', body: '' }); // Esto se ejecuta la primera vez useEffect(() => { // Llamamos a la función que carga los posts obtenerPosts(); }, []); // Aquí tenemos tres funciones porque son las tres operaciones que podemos hacer: // Leer, añadir y eliminar. // Es mejorable, pero funciona // Llamamos con axios a la api y ponemos lo obtenido en el estado const obtenerPosts = async () => { try { const response = await axios.get('http://localhost:4000/posts'); setPosts(response.data); } catch (error) { console.error('Error al obtener posts:', error); } }; // LLamamamos a la api con POST y los datos del formulario const agregarPost = async () => { try { await axios.post('http://localhost:4000/posts', nuevoPost); // Ponemos a cero el formulario setNuevoPost({ title: '', body: '' }); // Cargadmos los datos de la api (podríamos hacerlo directamente en el estado) obtenerPosts(); } catch (error) { console.error('Error al agregar post:', error); } }; // Llamamos a la api con DELETE const eliminarPost = async (id) => { try { await axios.delete(`http://localhost:4000/posts/${id}`); // Cargamos los datos de nuevo obtenerPosts(); } catch (error) { console.error('Error al eliminar post:', error); } }; return ( <div> <h1>Posts</h1> <ul> {/* Lista de todos los posts con su 'key */} {posts.map((post) => ( <li key={post.id}> <h2>{post.title}</h2> <p>{post.body}</p> <button onClick={() => eliminarPost(post.id)}>Eliminar</button> </li> ))} </ul> {/** Formulario, el change no llama a ninguna función, directamente cambia el estado en * los dos campos. Yo prefiero hacerlo con una sola función. */} <h2>Agregar nuevo post</h2> <input type="text" value={nuevoPost.title} onChange={(e) => setNuevoPost({ ...nuevoPost, title: e.target.value })} placeholder="Título" /> <textarea value={nuevoPost.body} onChange={(e) => setNuevoPost({ ...nuevoPost, body: e.target.value })} placeholder="Cuerpo" /> <button onClick={agregarPost}>Agregar post</button> </div> ); }; export default App;
db.json
{ "posts": [ { "id": "1", "title": "Post 1", "body": "Cuerpo del post 1" }, { "id": "29d4", "title": "Post 3", "body": "holi" }, { "id": "e4da", "title": "dfsdfsdfsd", "body": "asdasd" } ] }
Ejemplo useref
import React, { useRef } from "react"; function App() { // Crear una referencia con useRef const inputRef = useRef(null); // Función para obtener el valor actual del input const handleGetValue = () => { alert(`Valor actual del input: ${inputRef.current.value}`); }; // Función para cambiar el valor del input const handleChangeValue = () => { inputRef.current.value = "Nuevo valor dinámico"; alert("El valor del input ha sido cambiado"); }; return ( <div> <h1>Ejemplo de obtener y cambiar valor con useRef</h1> {/* Input con referencia */} <input ref={inputRef} type="text" placeholder="Escribe algo aquí..." /> <br /> {/* Botón para obtener el valor */} <button onClick={handleGetValue}>Obtener valor</button> {/* Botón para cambiar el valor */} <button onClick={handleChangeValue}>Cambiar valor</button> </div> ); } export default App;
Ejercicio Lista de la compra
Vamos a hacer un ejercicio para mantener una lista de la compra, sin API
Tenemos un campo de texto y un botón de añadir. Si escribimos algo y le damos a añadir lo veremos en una tabla debajo de ese botón.
Cada elemento de la lista de la compra tendrá un botón al lado para eliminarlo
Una cosa como esta:
Producto: [_________] [Añadir]
Lista
Patatas [Borrar]
Tomates [Borrar]
Bacon [Borrar]
Pasos a realizar:
¿Cuál es nuestro estado?
¿Qué componentes vamos a tener?
¿Cómo creamos nuestro ‘árbol’ y como intercambiamos la información?
Ejemplo contexto genérico
App
import React, { useState } from "react"; import ContextoCon from "./ContextoCon"; import IncrementButton from "./IncrementButton"; import DisplayCount from "./DisplayCount"; function CounterProvider({ children }) { const [count, setCount] = useState(0); return ( <ContextoCon valor={{ count, setCount }}> {children} </ContextoCon> ); } function App() { return ( <CounterProvider> <DisplayCount /> <IncrementButton /> </CounterProvider> ); } export default App;
Contexto
import { createContext } from 'react' const Contexto = createContext({}) export default Contexto;
ContextoCon
import Contexto from "./Contexto"; const ContextoCon= ({children,valor}) => { return <Contexto.Provider value={valor}> {children} </Contexto.Provider> } export default ContextoCon;
IncrementButton
import { useContext } from "react"; import Contexto from "./Contexto"; function IncrementButton() { const { count, setCount } = useContext(Contexto); return <button onClick={() => setCount(count + 1)}>Incrementar</button>; } export default IncrementButton;
DisplayButton
import { useContext } from "react"; import Contexto from "./Contexto"; function DisplayCount() { const { count } = useContext(Contexto); return <p>Contador: {count}</p>; } export default DisplayCount;
Ejercicio mostrar Posts
App
import React, { useState, useEffect } from "react"; import Post from "./Post"; import 'bootstrap/dist/css/bootstrap.min.css'; function App() { const [data, setData] = useState(null); useEffect(() => { fetch("https://jsonplaceholder.typicode.com/posts") .then((response) => response.json()) .then((json) => setData(json)); return () => { console.log("Limpieza de efecto (si aplica)"); }; }, []); // Solo se ejecuta una vez, al montar el componente. const removePost=(id)=>{ setData(data.filter(post=>post.id!=id)) } return ( <div> {data ? <table class="table table-striped"> <thead> <tr> <th>Id</th> <th>Title</th> <th>Body</th> <th>Action</th> </tr> </thead> <tbody> {data.map((post)=> <Post key={post.id} post={post} remove={removePost}/> )} </tbody> </table> : <button class="btn btn-primary"> <span class="spinner-border spinner-border-sm"></span> Cargando... </button>} </div> ); } export default App;
Post
const Post= ({post,remove}) => { return <tr> <td>{post.id}</td> <td>{post.title}</td> <td>{post.body.slice(0,20)}...</td> <td><button class="btn btn-danger" onClick={()=>{remove(post.id)}}>Borrar</button></td> </tr> } export default Post;
Ejercicios React
En el juego de los 100 botones vamos a hacer lo siguiente:
Tener un estado con las variables ‘numActual’ y ‘finalizado’. numActual sera 1 y finalizado falso
En los botones llamaremos a una función del padre (como en el ejemplo de trifulcas)
En esa función tenemos que comprobar si el número pulsado es el correcto. Si el número que me pasa el hijo es igual al actual, si es así sumamos 1 al actual.
Si no es así, finalizado true
Si el número es 100 finalizado true
Si alguien quiere tirar de renderizado condicional y si finalizado es true mostrar ‘juego acabado’ y si no los números
Quiero una página que tenga tres botones, cada uno con un nombre de un color y al pulsar el botón en un
me salga ‘Mi color preferido es el ‘ y el color pulsado.
Minicalculadora:
Dos cajas de texto para poner números. Cuando cambien los valores que debajo salga el valor de la suma y el de la multiplicación.
Dos tutoriales React
Ejemplo eventos
Boton
const Boton = ({numero,llamada}) => { {/* Llamo a la función que me pasan con el número del botón. Esto lo que hace es llamar a la función del padre con el valor del botón que se ha pulsado Estoy pasando información del hijo al padre */} return <button onClick={()=>llamada(numero)} className="btn btn-info">{numero}</button>; } export default Boton;
App
import logo from './logo.svg'; import './App.css'; // Componente importado desde un archivo import Despedida from './Despedida'; import Boton from './Boton'; import 'bootstrap/dist/css/bootstrap.min.css'; const generateRandomNumbers = () => { const arr = Array.from({ length: 100 }, (_, i) => i + 1); // Números del 1 al 100 for (let i = arr.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [arr[i], arr[j]] = [arr[j], arr[i]]; // Intercambiar elementos } return arr; }; const getNumber=(numero)=>{ console.log(numero) } const saludo=(nombre)=>{ console.log(nombre) console.log("Hola "+nombre+" que tal"); } // Componente Más o menos una función que nos devuelve una mezcla de HTML y JS function App() { // Creo un array de nombres const numeros=generateRandomNumbers(); return ( <div className="App"> {/* Paso al hijo una función para que se ejecute en un evento suyo */} {numeros.map((numero,i)=> <Boton numero={numero} key={i} llamada={getNumber}/> )} <Despedida nombre="Juan"/> {/* Aquí llamo a la función sin parámetros y nos pasará el evento */} <button onClick={saludo} >Pinchame</button> {/* Aquí uso la función flecha para pasar un parámetro propio */} <button onClick={()=>saludo("Ana")} >Pinchame</button> </div> ); } // Exportamos APP (y lo renderizamos en index.js) export default App;