React框架卡片搜索过滤返回空数组问题排查
React搜索过滤返回空数组问题排查
- 开发场景:基于React开发鸟类网页搜索引擎,在
Searchcard.js中通过三元运算实现搜索过滤逻辑 - 预期逻辑:搜索状态
search为空时展示全量卡片数据,search有输入值时按输入内容匹配过滤对应数据 - 异常现象:无输入时全量展示正常,输入搜索内容后页面无数据,存储过滤结果的
res变量始终返回空数组
初始错误过滤代码
const res = !search ? data : data.filter((dato) => dato.toString().toLowerCase().includes(search.toLocaleLowerCase()))
这段代码的问题是直接对数组项dato(对象类型)调用toString(),返回的是固定字符串[object Object],自然无法匹配搜索关键词。
第一次调整后的代码
const res = !search ? data : data.filter((dato) => dato.name.toString().toLowerCase().includes(search.toLocaleLowerCase()))
调整后依然返回空数组,调试确认API返回的原始data数据正常,但过滤结果始终为空。
相关代码文件
Searchcard.js(搜索页主组件)
import React from 'react' import { useState } from 'react' import {Cards} from '../cards/Cards' import { UseFetch } from '../UseFetch' export const Searchcard = () => { //hooks const [url, setUrl] = useState("https://aves.ninjas.cl/api/birds") const estado = UseFetch(url) /* 获取UseFetch返回的状态对象(加载状态、数据) */ const {cargando, data} = estado /* 从返回对象中解构加载状态和接口数据 */ const [search, setSearch] = useState("") // 捕获用户输入的搜索值 const searcher = (e) => { setSearch(e.target.value) console.log(e.target) } // 数据过滤逻辑 const res = !search ? data : data.filter((dato) => dato.name.toString().toLowerCase().includes(search.toLocaleLowerCase())) return ( <div> <input value={search} onChange={searcher} type="text" placeholder='¡Busca un pajaro!' className='form-control'></input> { cargando ? <h1>Cargando...</h1> : <div> <Cards data={res} /> {console.log(data)} {console.log(res)} </div> } </div> ) } export default Searchcard
UseFetch.js(自定义数据请求Hook)
import { useState, useEffect } from 'react' export const UseFetch = (url) => { const [resultado, setResultado] = useState({ cargando: true, dato: null }) useEffect( ()=>{ getData(url) },[url]) async function getData(url) { try{ setResultado({cargando: true, data:null}) const respues = await fetch(url) const data = await respues.json() setResultado({ cargando: false, data }) } catch(e){ console.log(e) } } return resultado }
cards.js(卡片列表组件)
import React, {useState} from 'react' import {Cardsbird} from './Cardsbird' import './Cards.css' import Paginacion from '../Pagination/Pagination' export const Cards = ({data}) => { const [actPag, setactPag] = useState(1) const [cardXpag] = useState(20) // 分页切片逻辑 const indUltimo = actPag * cardXpag; const indPrimero = indUltimo - cardXpag; const actCard = data.slice(indPrimero, indUltimo); // 切换页码 const paginate = numPag => setactPag(numPag); return ( <div className='container'> <ul className='cards'> {actCard.map(p=>( <li className='card-item' key={p.uid}> <Cardsbird url={p._links.self}/> </li> )) } <div className='container2'><Paginacion cardXpag={cardXpag} totalCards={data.length} paginate={paginate}/></div> </ul> </div> ) } export default Cards
cardsbird.js(单卡片渲染组件)
import React from 'react' import { UseFetch } from '../UseFetch' import Modal from './Modal' export const Cardsbird = ({url}) => { const estado = UseFetch(url) const {cargando, data} = estado return ( <div> { cargando ? <h1>Cargando...</h1> : <div className='card' style={{width:'14rem'}} data-bs-toggle="modal" data-bs-target={`#id${data.sort}`}> <div className='card-header'> <h5 className='card-title'>{data.name.spanish}</h5> </div> <div className='card-body'> <img src={data.images.main} alt={data.uid} /> </div> <Modal id={`id${data.sort}`} titulo={data.name.spanish} imagen={data.images.main} audio={data.audio.file} descripcion={data.iucn.description} habitat={data.habitat} tamaño={data.size} mapa={data.map.image} /> </div> } </div> ) } export default Cardsbird
问题根因
从cardsbird.js的渲染逻辑可以看出,接口返回的列表项中name字段不是字符串,而是一个多语言对象,结构为name: { spanish: "鸟类西语名称", english: "鸟类英语名称", ... }。
过滤时直接对dato.name这个对象调用toString(),得到的结果是固定字符串[object Object],永远不可能匹配用户输入的搜索关键词,因此过滤结果始终为空数组。
修复方案
修改过滤逻辑,指定要匹配的name下的具体文本字段,比如匹配西语名称:
const res = !search ? data : data.filter((dato) => dato.name.spanish.toLowerCase().includes(search.toLocaleLowerCase()) )
如果需要同时匹配多语言名称,可以扩展判断逻辑:
const res = !search ? data : data.filter((dato) => { const keyword = search.toLocaleLowerCase() return dato.name.spanish.toLowerCase().includes(keyword) || dato.name.english.toLowerCase().includes(keyword) // 可继续添加其他需要匹配的字段 })
额外优化点:
Cards组件中分页状态actPag默认值为1,建议在搜索关键词search变化时重置actPag为1,避免出现搜索后当前页码无数据的问题。
内容的提问来源于stack exchange,提问作者Ffuentes
相关产品推荐
相关产品推荐

