我想在我的应用程序中具有双重搜索功能。一次搜索,按书名过滤书籍。而另一个,按流派过滤书籍。两个搜索过滤器应该一起工作(如果提供了搜索词,它应该按标题和流派过滤掉)。
但是,我在应用流派搜索过滤器时遇到了困难。
** 注意**:创建时,每个流派标签的分配方式与id
其所标记的书籍相同。通过这种方式,我可以提取与正在搜索的类型相关的所有书籍。
对象:
book = { id: "id", title: "title", author: "author"}
genre = { id: "id", label: "label" }
父组件
export default function Books() {
const [books, setBooks] = useState([])
const [searchTitle, setSearchTitle] = useState("")
const [genres, setGenres] = useState([])
const [searchGenre, setSearchGenre] = useState("")
useEffect(() => {
fetch(`https://www.someapi.com/books`)
.then(r => r.json())
.then(setBooks)
}, [])
function handleAllGenres(val){
setGenres([...genres, val])
}
const filterGenres = genres.filter(genre => {
return genre.label.toLowerCase().includes(searchGenre.toLowerCase())
})
const filterBooks = books.filter(book => {
return book.title.toLowerCase().includes(searchTitle.toLowerCase())
})
const filterBookGenres = filterBooks.filter(book => {
if (searchGenres.length > 0) {
return filterGenres.some(genre => book.id === genre.id)
} else {
return books
}
})
const book = filterBookGenres.map(book => {
return (
<Book
key={book.id}
book={book}
genres={genres}
onAddGenre={handleAllGenres}
/>
)
})
return (
<div className="main-container">
<SearchTitle
searchTitle={searchTitle}
onSearchTitle={setSearchTitle}
/>
<SearchGenre
searchGenre={searchGenre}
onSearchGenre={setSearchGenre}
/>
{book}
</div>
);
}
子组件:
export default function Book({ book, onAddGenre })
const [genreTags, setGenreTags] = useState([])
function handleAddGenre(e) {
const val = {
id: book.id,
label: e.target.value,
}
if (e.key === 'Enter' && val) {
if (genreTags.find(genre => genre.toLowerCase() === val.toLowerCase())) {
return
}
setGenreTags([...genreTags, val])
onAddGenre(val)
e.target.value = ""
}
}
return (
<div className="book-div">
<p>{title}</p>
<p>Written By: {author}</p>
</div>
<div className="tag-div">
<ul>
{ genreTags && genreTags.map(tag => {
return <li key={uuid()}> {tag.label} </li>
})}
</ul>
</div>
<input
type="text"
placeholder="Add a genre"
onKeyDown={handleAddGenre}
/>
);
}
搜索组件:
export default function SearchTitle({ searchTitle, onSearchTitle }) {
return (
<div className="search">
<input
id="name-input"
placeholder="Search by title"
value={search}
onChange={e => onSearch(e.target.value)}
/>
</div>
);
}
export default function SearchGenre({ searchGenre, onSearchGenre }) {
return (
<div className="search">
<input
id="tag-input"
placeholder="Search by genre"
value={searchGenre}
onChange={e => onSearchTag(e.target.value)}
/>
</div>
)
}
更新:搜索功能现在可以使用,但我注意到我的标签在我尝试使用任一搜索功能后消失了。例如,如果我输入搜索值并过滤图书列表,然后删除我的搜索词,我的标签就会消失。我想是因为这些书被重新渲染了?
有没有办法防止这种重新渲染或防止我的标签在玩弄我的搜索功能后消失?
所有的帮助表示赞赏。谢谢!
很难说,因为我看不到 onClick 处理程序内部发生了什么(它们位于不同的组件中)。我马上就看到了一个可能的问题(这很奇怪,考虑到你说类型是问题而不是标题搜索)。在filterBooks
你有book => { return title.toLowerCase()...
,但应该是book => { return book.title.toLowerCase()...
此外,在此代码示例中,您没有设置setGenres
. 是genres
状态空?
编辑
有没有办法防止这种重新渲染或防止我的标签在玩我的搜索功能后消失?
是的,在我们刷新页面或卸载并重新安装Books
组件之前,我们可以使用一个变通解决方案。对象是可变数据结构,因此您可以改变它们以添加新键(“标签”)。即使Book
对象卸载并重新安装,这些也会持续存在。我们可以做到这一点handleAddGenre
的Book.js
,像这样:
function handleAddGenre(e) {
const val = {
id: book.id,
label: e.target.value
};
if (e.key === "Enter" && val) {
if (
/**
* Note that I made a small change here,
* adding 'labels' before the two toLowerCase methods
*/
genreTags.find(
(genre) => genre.label.toLowerCase() === val.label.toLowerCase()
)
) {
return;
}
/**
* we mutate the book object here.
* This will persist until we reset the books state,
* so searching doesn't make it disappear.
*/
book.tags = book.tags ? [...book.tags, val] : [val];
setGenreTags([...genreTags, val]);
onAddGenre(val);
e.target.value = "";
}
}
然后,我们只需要相应地更改渲染,因为它应该遍历书的新tag
键以找到所有新标签
<ul>
{book.tags &&
book.tags.map((tag) => {
return <li key={uuid()}> {tag.label} </li>;
})}
</ul>
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句