Vimos en el concepto anterior una situación común de varios controles select que dependen entre si.
Vamos a crear un control select que muestre distintos rubros (por ejemplo: Microprocesadores, Placas de video, Gabinetes etc), luego cuando el operador selecciona un rubro, se debe actualizar otro control select que muestra todos los artículos que pertenecen a dicho rubro, por ejemplo si seleccionar Microprocesadores el segundo select puede mostrar Intel Core I5, Intel Core I7 etc., pero ahora los datos se encontrarán en un servidor web y haremos peticiones con la función fetch. El servidor nos responderá con formato JSON.
Como primer paso creamos una aplicación con create-react-app:
npx create-react-app proyecto021
Veamos el código de nuestra aplicación donde se encuentra la funcionalidad del formulario.
App.js
import './App.css'; import { useState, useEffect } from 'react'; function App() { const [rubros, setRubros] = useState([]) const [rubroSeleccionado, setRubroSeleccionado] = useState({}) useEffect(() => { fetch('https://www.scratchya.com.ar/reactya/proyecto021/recuperarrubros.php') .then((response) => { return response.json() }) .then((rub) => { setRubros(rub) setRubroSeleccionado(rub[0]) }) }, []) const [articulosRubro, setarticulosRubro] = useState([]) const [articuloSeleccionado, setArticuloSeleccionado] = useState([]) useEffect(() => { if (rubroSeleccionado.codigo) fetch('https://www.scratchya.com.ar/reactya/proyecto021/recuperararticulos.php?rubro=' + rubroSeleccionado.codigo) .then((response) => { return response.json() }) .then((art) => { setarticulosRubro(art) setArticuloSeleccionado(art[0]) }) }, [rubroSeleccionado]) function cambiarRubro(e) { const rubroSelect = rubros.find(r => Number.parseInt(r.codigo) === Number.parseInt(e.target.value)) setRubroSeleccionado(rubroSelect) } function cambiarArticulo(e) { setArticuloSeleccionado(articulosRubro.find(articulo => Number.parseInt(articulo.codigo) === Number.parseInt(e.target.value))) } return ( <div className="formulario"> <div> <select value={rubroSeleccionado.codigo} onChange={cambiarRubro}> {rubros.map(rubro => ( <option key={rubro.codigo} value={rubro.codigo}>{rubro.nombre}</option> ))} </select> </div> <div> <select value={articuloSeleccionado.codigo} onChange={cambiarArticulo}> {articulosRubro.map(articulo => ( <option key={articulo.codigo} value={articulo.codigo}>{articulo.nombre}</option> ))} </select> </div> <div> <ul> <li>Rubro:<strong>{rubroSeleccionado.nombre}</strong></li> <li>Articulo:<strong>{articuloSeleccionado.nombre}</strong></li> <li>Precio:<strong>{articuloSeleccionado.precio}</strong></li> </ul> </div> </div> ); } export default App;
Importamos las funciones useState y useEffect:
import { useState, useEffect } from 'react';
Mediante un hook de efecto recuperamos todos los rubres del servidor y procedemos a actualizar la variable rubros:
const [rubros, setRubros] = useState([]) const [rubroSeleccionado, setRubroSeleccionado] = useState({}) useEffect(() => { fetch('https://www.scratchya.com.ar/reactya/proyecto021/recuperarrubros.php') .then((response) => { return response.json() }) .then((rub) => { setRubros(rub) setRubroSeleccionado(rub[0]) }) }, [])
Cuando los datos llegan del servidor procedemos a mostrar todos los rubros y marcar como seleccionado el primero:
<select value={rubroSeleccionado.codigo} onChange={cambiarRubro}> {rubros.map(rubro => ( <option key={rubro.codigo} value={rubro.codigo}>{rubro.nombre}</option> ))} </select>
De forma similar recuperamos todos los artículos que coinciden con el rubro seleccionado actual:
const [articulosRubro, setarticulosRubro] = useState([]) const [articuloSeleccionado, setArticuloSeleccionado] = useState([]) useEffect(() => { if (rubroSeleccionado.codigo) fetch('https://www.scratchya.com.ar/reactya/proyecto021/recuperararticulos.php?rubro=' + rubroSeleccionado.codigo) .then((response) => { return response.json() }) .then((art) => { setarticulosRubro(art) setArticuloSeleccionado(art[0]) }) }, [rubroSeleccionado])
Como vemos el servidor nos retorna solo los artículos del rubro seleccionado actualmente. Luego al modificar la variable 'articulosRubro' se actualiza el control select en forma automática:
<select value={articuloSeleccionado.codigo} onChange={cambiarArticulo}> {articulosRubro.map(articulo => ( <option key={articulo.codigo} value={articulo.codigo}>{articulo.nombre}</option> ))} </select>
el evento de cambio de rubro dispara la función 'cambiarRubro' donde recuperamos el nuevo rubro seleccionado y actualizamos la variable 'rubroSeleccionado', el cual dispara nuevamente el hook de efecto que recupera los artículos del nuevo rubro seleccionado:
function cambiarRubro(e) { const rubroSelect = rubros.find(r => Number.parseInt(r.codigo) === Number.parseInt(e.target.value)) setRubroSeleccionado(rubroSelect) } function cambiarArticulo(e) { setArticuloSeleccionado(articulosRubro.find(articulo => Number.parseInt(articulo.codigo) === Number.parseInt(e.target.value))) }
En el archivo de la hoja de estilo.
App.css
select { padding: 0.5em; margin: 0.5em; } .formulario { display: flex; flex-direction: column; align-items: center; justify-content: center; }
Podemos probar ahora la aplicación: aquí