You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ReactJS如何匹配两数组id实现双重搜索并解决搜索后标签消失问题

问题根源
  • 你把每个图书的genre标签存在了<Book>子组件的内部state里,当搜索过滤时,不符合条件的<Book>组件会被直接卸载,清空搜索词后重新渲染的是全新的<Book>实例,内部state自然会重置,导致标签消失
  • 你父组件其实已经维护了全量的genres全局数组,完全可以直接复用这个数据,不需要在子组件重复存状态
具体修改方案

1. 修改子组件,删除内部标签状态,从全局genres中读取当前图书的标签

这样标签数据存在父组件,不会因为子组件被卸载丢失:

export default function Book({ book, genres, onAddGenre }) {
    // 直接从全局genres过滤当前图书对应的标签,无需内部state维护
    const genreTags = genres.filter(genre => genre.id === book.id)

    function handleAddGenre(e) {
        const val = {
            id: book.id,
            label: e.target.value,
        }

        if (e.key === 'Enter' && val.label) {
            // 查重逻辑改为从全局genres判断,避免重复添加
            if (genres.find(genre => genre.id === book.id && genre.label.toLowerCase() === val.label.toLowerCase())) {
              return
            }
            onAddGenre(val)
            e.target.value = ""
        }
    }

    return (
        <>
            <div className="book-div">
                <p>{book.title}</p>
                <p>Written By: {book.author}</p>
            </div>
            <div className="tag-div">
                <ul> 
                    { genreTags.map(tag => {
                        // 不要用uuid生成key,避免每次渲染都重建节点
                        return <li key={`${book.id}-${tag.label}`}> {tag.label} </li>  
                    })}
                </ul>
            </div>
            <input 
                type="text" 
                placeholder="Add a genre"
                onKeyDown={handleAddGenre} 
            />
        </>
    );
}

2. 修复现有代码的其他错误点

这些错误会导致功能无法正常运行,需要同步修改:

  • 父组件过滤逻辑里的searchGenres.length是笔误,改为searchGenre.length
  • SearchTitle组件里的value={search}改为value={searchTitle},onSearch改为onSearchTitle
  • SearchGenre组件里的onSearchTag改为onSearchGenre
  • 可以把父组件的三段过滤逻辑合并,更清晰不容易出错:
// 替换原来的filterGenres、filterBooks、filterBookGenres逻辑
const filteredBooks = books.filter(book => {
  // 匹配书名条件
  const matchTitle = book.title.toLowerCase().includes(searchTitle.toLowerCase())
  // 匹配genre条件,没有输入genre时直接通过
  const matchGenre = searchGenre.trim() === "" 
    ? true 
    : genres.some(genre => genre.id === book.id && genre.label.toLowerCase().includes(searchGenre.toLowerCase()))
  return matchTitle && matchGenre
})

// 渲染时直接遍历filteredBooks即可
const book = filteredBooks.map(book => {
  return (
      <Book 
          key={book.id} 
          book={book}
          genres={genres}
          onAddGenre={handleAllGenres}
      />
  )
})

3. 可选优化:避免组件不必要重渲染

如果希望减少过滤时的组件重渲染开销,可以用React.memo包裹<Book>组件,只要props不变就不会触发重渲染:

import { memo } from 'react'
export default memo(function Book({ book, genres, onAddGenre }) {
  // 原有组件逻辑
})

内容的提问来源于stack exchange,提问作者may cheynack

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.11 14:00:00