Soy nuevo en React (y todavía nuevo en JS también), y estoy tratando de construir mi primer proyecto React. Obtengo una API, renderizo algunos elementos y construyo una barra de búsqueda que filtra los elementos renderizados.
Mi función de filtrado funciona más o menos, y dentro de ella almaceno los resultados filtrados en let result
, pero ¿cómo debo acceder a esos resultados desde la parte de retorno (área JSX, creo) para recorrerlos?
Este es mi código:
import React, { useState, useEffect } from "react"; import ListItem from "./ListItem"; const List = () => { const [data, setData] = useState(); const [input, setInput] = useState(""); const onInputChange = (event) => { setInput(event.target.value); const value = event.target.value.toLowerCase(); let result = []; result = data.filter((item) => item.name.toLowerCase().includes(value.toLowerCase()) ); setInput(result); }; useEffect(() => { const getData = async () => { const response = await fetch( "https://rickandmortyapi.com/api/character/" ); const obj = await response.json(); setData(obj.results); }; getData(); }, []); return ( <div> <input type="text" name={input} onChange={onInputChange}></input> {data && data.map((item) => { return <ListItem key={item.id} character={item} />; })} </div> ); }; export default List;
Hasta ahora, solo puedo recorrer la input
que contiene los results
, como esta input && input.map((item)
, pero eso me da una matriz vacía cuando se carga la página, hasta que hago una búsqueda.
Necesita usar una variable para almacenar datos después del filtro:
const [data, setData] = useState([]); const onInputChange = (event) => { setInput(event.target.value); }; const result = data.filter((item) => item.name.toLowerCase().includes(input.toLowerCase()) ); return ( ... {result?.map((item) => { <ListItem key={item.id} character={item} />; })} ... )
Simplemente inicializa la entrada como una cadena, así que solo mantenga la entrada para mantener el valor de entrada, no los datos de resultado. Puede crear otro estado para mantener el resultado O volver a colocar los datos del resultado en la variable de datos.
Aquí te muestro cómo mantener los datos de resultados separados.
import React, { useState, useEffect } from "react"; import ListItem from "./ListItem"; const List = () => { const [data, setData] = useState(); const [searchResult, setSearchResult] = useState(); const [input, setInput] = useState(""); const onInputChange = (event) => { setInput(event.target.value); const value = event.target.value.toLowerCase(); let result = []; result = data.filter((item) => item.name.toLowerCase().includes(value.toLowerCase()) ); setSearchResult(result); }; useEffect(() => { const getData = async () => { const response = await fetch( "https://rickandmortyapi.com/api/character/" ); const obj = await response.json(); setData(obj.results); }; getData(); }, []); return ( <div> <input type="text" name={input} onChange={onInputChange}></input> {input===""? data && data.map((item) => { return <ListItem key={item.id} character={item} />; }): searchResult && searchResult.map((item) => { return <ListItem key={item.id} character={item} />; }) } </div> ); }; export default List;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Esto está separando sus datos originales y el resultado de la búsqueda diferente.
Una posible solución sería filtrar durante el renderizado,
En este escenario, solo necesitaría guardar el valor de entrada (onInputChange):
const onInputChange = (event) => { setInput(event.target.value); };
Luego, al renderizar, necesitaría agregar la lógica de filtrado:
{ // if input is not empty data .filter(item => item.name.includes(input.toLowerCase())) .map((item) => { return <ListItem key={item.id} character={item} />; })