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í