React:搜索和过滤功能出现问题
React: issue with the search and filter function
我正在开发一个组件,它应该能够:
按输入搜索 - 使用输入字段将在触发 onBlur 事件后调用一个函数。在 onBlur 事件之后,startSearch() 方法将 运行.
按 select 流派过滤 - 从其他组件,用户可以 select 流派列表中的流派。 onClick 事件后 startFilter() 方法将 运行.
好消息:
我得到了上面的 2 个函数。
坏消息:
以上 2 个功能不能正常工作。请看下面的代码。下面的 2 个调用有效,但前提是我将其中的 2 个注释掉。我尝试以各种方式调整 startSearch() 方法,但我一直走到一面大胖墙。
//////Searching works
//////this.filter(this.state.searchInput);
//Filtering works
this.startFilter(this.state.searchInput);
问题
如何让 filter/search 方法起作用?。不幸的是,简单地将它们放在 if/else 中并不是解决方案(请参阅代码中的注释)。
import { Component } from 'preact';
import listData from '../../assets/data.json';
import { Link } from 'preact-router/match';
import style from './style';
export default class List extends Component {
state = {
selectedStreamUrl: '',
searchInput: '',
showDeleteButton: false,
searchByGenre: false,
list: []
};
startFilter(input, filterByGenre) {
this.setState({
searchByGenre: true,
searchInput: input,
showDeleteButton: true
});
alert('startFilter ');
console.log(this.state.searchByGenre);
/////////---------------------------------
document.getElementById('searchField').disabled = false;
document.getElementById('searchField').value = input;
document.getElementById('searchField').focus();
// document.getElementById('searchField').blur()
document.getElementById('searchField').disabled = true;
console.log(input);
this.filter(input);
}
//search
startSearch(input) {
alert('startSearch ');
console.log(this.state.searchByGenre);
//komt uit render()
if (!this.state.searchByGenre) {
//check for input
this.setState({
searchInput: input.target.value,
showDeleteButton: true
});
//Searching works
//this.filter(this.state.searchInput);
//Filtering works
this.startFilter(this.state.searchInput);
// DOESNT WORK:
// if (this.state.searchInput != "") {
// this.filter(this.state.searchInput);
// } else {
// this.startFilter(this.state.searchInput);
// }
}
}
setAllLists(allLists) {
console.log('setAllLists');
console.log(this.state.searchByGenre);
this.setState({ list: allLists });
//document.body.style.backgroundColor = "red";
}
filter(input) {
let corresondingGenre = [];
let filteredLists = listData.filter(item1 => {
var test;
if (this.state.searchByGenre) {
alert('--this.state.searchByGenre');
//filterByGenre
//& item1.properties.genre == input
for (var i = 0; i < item1.properties.genre.length; i++) {
if (item1.properties.genre[i].includes(input)) {
corresondingGenre.push(item1);
test = item1.properties.genre[i].indexOf(input) !== -1;
return test;
}
this.setState({ list: corresondingGenre });
}
} else {
//searchByTitle
alert('--default');
test = item1.title.indexOf(input.charAt(0).toUpperCase()) !== -1;
}
return test;
});
console.log('filterdLists:');
console.log(filteredLists);
console.log('corresondingGenre:');
console.log(corresondingGenre);
//alert(JSON.stringify(filteredLists))
this.setState({ list: filteredLists });
}
removeInput() {
console.log('removeInput ');
console.log(this.state.searchByGenre);
this.setState({
searchInput: '',
showDeleteButton: false,
searchByGenre: false
});
document.getElementById('searchField').disabled = false;
this.filter(this.state.searchInput);
}
render() {
//alle 's komen in deze array, zodat ze gefilterd kunnen worden OBV title.
if (
this.state.list === undefined ||
(this.state.list.length == 0 && this.state.searchInput == '')
) {
//init list
console.log('render ');
console.log(this.state.searchByGenre);
this.filter(this.state.searchInput);
}
return (
<div class={style.list_container}>
<input
class={style.searchBar}
type="text"
id="searchField"
placeholder={this.state.searchInput}
onBlur={this.startSearch.bind(this)}
/>
{this.state.searchByGenre ? <h1>ja</h1> : <h1>nee</h1>}
{this.state.showDeleteButton ? (
<button class={style.deleteButton} onClick={() => this.removeInput()}>
Remove
</button>
) : null}
{this.state.list.map((item, index) => {
return (
<div>
<p>{item.title}</p>
</div>
);
})}
</div>
);
}
}
两种方式:
更改对构造函数的绑定(以及状态!)
constructor(props) {
super(props);
this.state = { searchByGenre: true }
this.startSeach = startSearch.bind(this);
}
startSearch(searchByGenre) {
//This is false after the call
console.log(this.state.searchByGenre)
}
render() {
return (
<input class={style.searchBar} type="text" id="searchField" placeholder="Search" value={this.state.searchInput} onBlur={this.startSearch} >
</input>
)
}
这样你就可以使用带参数的 startSearch
:
<input class={style.searchBar}
type="text"
id="searchField"
placeholder="Search"
value={this.state.searchInput}
onBlur={() => this.startSearch(this.state.searchByGenre)}
>
OR 你可以将 startSearch
更改为箭头函数,并从构造函数中删除绑定:
startSearch = (searchByGenre) => {
//This is false after the call
console.log(this.state.searchByGenre)
}
你可以看看为什么会这样here。
编辑:link讲的是typeScript,忽略它,关注箭头function/bind部分
你问的问题不清楚。但是请尽量明确您的组件以帮助调试问题。例如,使用构造函数并在其中声明您的组件状态。还要为那里的事件做 .bind 以使其简洁。
以下示例在触发 onBlur 事件时捕获状态变量为真,这与其初始状态值相同:
class List extends React.Component {
constructor(props) {
super(props);
this.state = {
searchByGenre: true
};
this.startSearch = this.startSearch.bind(this);
}
startSearch() {
// This value is true
console.log(this.state.searchByGenre)
}
render() {
return (
<input
type="text"
id="searchField"
placeholder="Search"
value={this.state.searchInput}
onBlur={this.startSearch}
/>
)
}
要使您的搜索和过滤器正常工作,您需要两个数组。
state = {
selectedStreamUrl: "",
searchInput: "",
showDeleteButton: false,
// searchByGenre: false, // removed, will use filter by from a list
// by default both arrays have the same value
list: listData, // holds the original data, doesn't change
filteredList: listData, // holds filterd list, filtered when the user types in input
// by default filter by title, will change when user, use a value from a list
filterBy: 'title',
}
您的搜索函数将使用 this.state.filterBy
值来过滤数组。无需创建多个函数。这为您提供了灵活性,因为您可以使用下拉列表中的多个值进行过滤,而无需更改代码。
startSearch = (value) => {
const search = value.toLowerCase();
// get filter value title, genre, etc
const searchKey = this.state.filterBy;
this.setState({
searchInput: value,
filteredList: this.state.list.filter(item => {
// filter base on key item['title'] or item['genre'] etc
return item && item[searchKey].toLowerCase().includes(search)
}),
showDeleteButton: !!value,
})
}
删除输入功能
removeInput = () => {
this.setState({
filterBy: 'title',
showDeleteButton: false,
searchInput: '',
}, () => this.startSearch(this.state.searchInput));
}
我看到你做了很多 document.getElementById("searchField").disabled = false;
。不要直接操作 dom,让 React 为您管理。
查看下面的演示
h1, p {
font-family: Lato;
}
.container {
display: flex;
flex-direction: row;
border-bottom-style: solid;
margin-bottom: 5px;
}
.image-container {
flex-grow: 0;
}
.info-container {
flex-grow: 1;
margin-left: 10px
}
.title {
margin-top: 0;
}
.cover {
width: 60px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.0/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.21.1/babel.min.js"></script>
<div id="root"></div>
<script type="text/babel">
const style = {};
const listData = [
{
"vote_count": 806,
"id": 420817,
"video": false,
"vote_average": 7.2,
"title": "Aladdin",
"popularity": 476.676,
"poster_path": "/3iYQTLGoy7QnjcUYRJy4YrAgGvp.jpg",
"original_language": "en",
"original_title": "Aladdin",
"genre": "Adventure",
"backdrop_path": "/v4yVTbbl8dE1UP2dWu5CLyaXOku.jpg",
"adult": false,
"overview": "A kindhearted street urchin named Aladdin embarks on a magical adventure after finding a lamp that releases a wisecracking genie while a power-hungry Grand Vizier vies for the same lamp that has the power to make their deepest wishes come true.",
"release_date": "2019-05-22"
},
{
"vote_count": 70,
"id": 373571,
"video": false,
"vote_average": 6.4,
"title": "Godzilla: King of the Monsters",
"popularity": 143.161,
"poster_path": "/pU3bnutJU91u3b4IeRPQTOP8jhV.jpg",
"original_language": "en",
"original_title": "Godzilla: King of the Monsters",
"genre": "Action",
"backdrop_path": "/mzRJpkWPjXdXak0WCc8ZxVH4hug.jpg",
"adult": false,
"overview": "The new story follows the heroic efforts of the crypto-zoological agency Monarch as its members face off against a battery of god-sized monsters, including the mighty Godzilla, who collides with Mothra, Rodan, and his ultimate nemesis, the three-headed King Ghidorah. When these ancient super-species—thought to be mere myths—rise again, they all vie for supremacy, leaving humanity’s very existence hanging in the balance.",
"release_date": "2019-05-29"
},
{
"vote_count": 984,
"id": 447404,
"video": false,
"vote_average": 7,
"title": "Pokémon Detective Pikachu",
"popularity": 109.979,
"poster_path": "/wgQ7APnFpf1TuviKHXeEe3KnsTV.jpg",
"original_language": "en",
"original_title": "Pokémon Detective Pikachu",
"genre": "Mystery",
"backdrop_path": "/nDP33LmQwNsnPv29GQazz59HjJI.jpg",
"adult": false,
"overview": "In a world where people collect pocket-size monsters (Pokémon) to do battle, a boy comes across an intelligent monster who seeks to be a detective.",
"release_date": "2019-05-03"
},
{
"vote_count": 136,
"id": 531309,
"video": false,
"vote_average": 5.6,
"title": "Brightburn",
"popularity": 108.875,
"poster_path": "/sJWwkYc9ajwnPRSkqj8Aue5JbKz.jpg",
"original_language": "en",
"original_title": "Brightburn",
"genre": "Horror",
"backdrop_path": "/uHEI6v8ApQusjbaRZ8o7WcLYeWb.jpg",
"adult": false,
"overview": "What if a child from another world crash-landed on Earth, but instead of becoming a hero to mankind, he proved to be something far more sinister?",
"release_date": "2019-05-09"
},
{
"vote_count": 570,
"id": 527641,
"video": false,
"vote_average": 8.1,
"title": "Five Feet Apart",
"popularity": 72.32,
"poster_path": "/kreTuJBkUjVWePRfhHZuYfhNE1T.jpg",
"original_language": "en",
"original_title": "Five Feet Apart",
"genre": "Romance",
"backdrop_path": "/27ZkYMWynuK2qiDP6awc3MsCaOs.jpg",
"adult": false,
"overview": "Seventeen-year-old Stella spends most of her time in the hospital as a cystic fibrosis patient. Her life is full of routines, boundaries and self-control -- all of which get put to the test when she meets Will, an impossibly charming teen who has the same illness. There's an instant flirtation, though restrictions dictate that they must maintain a safe distance between them. As their connection intensifies, so does the temptation to throw the rules out the window and embrace that attraction.",
"release_date": "2019-03-15"
},
{
"vote_count": 162,
"id": 449562,
"video": false,
"vote_average": 6.1,
"title": "The Hustle",
"popularity": 71.346,
"poster_path": "/qibqW5Dnvqp4hcEnoTARbQgxwJy.jpg",
"original_language": "en",
"original_title": "The Hustle",
"genre": "Comedy",
"backdrop_path": "/s6awXOxTKYQLSktiIJfI3969dZH.jpg",
"adult": false,
"overview": "Two female scam artists, one low rent and the other high class, compete to swindle a naïve tech prodigy out of his fortune. A remake of the 1988 comedy \"Dirty Rotten Scoundrels.\"",
"release_date": "2019-05-09"
},
{
"vote_count": 88,
"id": 504608,
"video": false,
"vote_average": 7.7,
"title": "Rocketman",
"popularity": 66.812,
"poster_path": "/f4FF18ia7yTvHf2izNrHqBmgH8U.jpg",
"original_language": "en",
"original_title": "Rocketman",
"genre": "Drama",
"backdrop_path": "/oAr5bgf49vxga9etWoQpAeRMvhp.jpg",
"adult": false,
"overview": "The story of Elton John's life, from his years as a prodigy at the Royal Academy of Music through his influential and enduring musical partnership with Bernie Taupin.",
"release_date": "2019-05-22"
},
{
"vote_count": 124,
"id": 505600,
"video": false,
"vote_average": 7,
"title": "Booksmart",
"popularity": 57.801,
"poster_path": "/Awyg5IdELQV3sBoErhJ9QVcX8TA.jpg",
"original_language": "en",
"original_title": "Booksmart",
"genre": "Drama, Comedy",
"backdrop_path": "/wcAqndL2MkIjPrCrYeuE794weNE.jpg",
"adult": false,
"overview": "Two academic teenage superstars realize, on the eve of their high school graduation, that they should have worked less and played more. Determined to never fall short of their peers, the girls set out on a mission to cram four years of fun into one night.",
"release_date": "2019-05-24"
},
{
"vote_count": 10,
"id": 502416,
"video": false,
"vote_average": 4.8,
"title": "Ma",
"popularity": 55.328,
"poster_path": "/6n7ASmQ1wY2cxTubFFGlcvPpyk7.jpg",
"original_language": "en",
"original_title": "Ma",
"genre": "Comedy, Horror",
"backdrop_path": "/mBOv5YrX5QGr5CusK0PKSHuxOt9.jpg",
"adult": false,
"overview": "Sue Ann is a loner who keeps to herself in her quiet Ohio town. One day, she is asked by Maggie, a new teenager in town, to buy some booze for her and her friends, and Sue Ann sees the chance to make some unsuspecting, if younger, friends of her own. She offers the kids the chance to avoid drinking and driving by hanging out in the basement of her home. But there are some house rules: One of the kids has to stay sober. Don’t curse. Never go upstairs. And call her “Ma.” But as Ma’s hospitality starts to curdle into obsession, what began as a teenage dream turns into a terrorizing nightmare, and Ma’s place goes from the best place in town to the worst place on earth.",
"release_date": "2019-05-29"
},
{
"vote_count": 88,
"id": 535581,
"video": false,
"vote_average": 5.9,
"title": "The Dead Don't Die",
"popularity": 52.857,
"poster_path": "/ycMSfP8KRFsVUWfbSxSFpD97QfD.jpg",
"original_language": "en",
"original_title": "The Dead Don't Die",
"genre": "Comedy, Horror",
"backdrop_path": "/cXyfAViYly0Lk2CVpEKgYbt9wKQ.jpg",
"adult": false,
"overview": "In a small peaceful town, zombies suddenly rise to terrorize the town. Now three bespectacled police officers and a strange Scottish morgue expert must band together to defeat the undead.",
"release_date": "2019-05-15"
},
{
"vote_count": 0,
"id": 320288,
"video": false,
"vote_average": 0,
"title": "Dark Phoenix",
"popularity": 52.433,
"poster_path": "/kZv92eTc0Gg3mKxqjjDAM73z9cy.jpg",
"original_language": "en",
"original_title": "Dark Phoenix",
"genre": "Action, Science Fiction",
"backdrop_path": "/A2oPzeKjSpCovYLqoDDXFbrJgyS.jpg",
"adult": false,
"overview": "The X-Men face their most formidable and powerful foe when one of their own, Jean Grey, starts to spiral out of control. During a rescue mission in outer space, Jean is nearly killed when she's hit by a mysterious cosmic force. Once she returns home, this force not only makes her infinitely more powerful, but far more unstable. The X-Men must now band together to save her soul and battle aliens that want to use Grey's new abilities to rule the galaxy.",
"release_date": "2019-06-05"
},
{
"vote_count": 10,
"id": 496243,
"video": false,
"vote_average": 9.4,
"title": "Parasite",
"popularity": 46.835,
"poster_path": "/7IiTTgloJzvGI1TAYymCfbfl3vT.jpg",
"original_language": "ko",
"original_title": "기생충",
"genre": "Drama, Comedy",
"backdrop_path": "/ny5aCtglk2kceGAuAdiyqbhBBAf.jpg",
"adult": false,
"overview": "All unemployed, Ki-taek's family takes peculiar interest in the wealthy and glamorous Parks for their livelihood until they get entangled in an unexpected incident.",
"release_date": "2019-05-30"
},
{
"vote_count": 71,
"id": 526050,
"video": false,
"vote_average": 6.2,
"title": "Little",
"popularity": 43.334,
"poster_path": "/4MDB6jJl3U7xK1Gw64zIqt9pQA4.jpg",
"original_language": "en",
"original_title": "Little",
"genre": "Comedy, Fantasy",
"backdrop_path": "/tmM78qRhpg0i2Cky8Q8hXKASOXY.jpg",
"adult": false,
"overview": "A woman receives the chance to relive the life of her younger self, at a point in her life when the pressures of adulthood become too much for her to bear.",
"release_date": "2019-04-04"
},
{
"vote_count": 1181,
"id": 329996,
"video": false,
"vote_average": 6.6,
"title": "Dumbo",
"popularity": 39.349,
"poster_path": "/279PwJAcelI4VuBtdzrZASqDPQr.jpg",
"original_language": "en",
"original_title": "Dumbo",
"genre": "Adventure, Animation, Fantasy",
"backdrop_path": "/5tFt6iuGnKapHl5tw0X0cKcnuVo.jpg",
"adult": false,
"overview": "A young elephant, whose oversized ears enable him to fly, helps save a struggling circus, but when the circus plans a new venture, Dumbo and his friends discover dark secrets beneath its shiny veneer.",
"release_date": "2019-03-27"
},
{
"vote_count": 19,
"id": 412117,
"video": false,
"vote_average": 6.5,
"title": "The Secret Life of Pets 2",
"popularity": 38.485,
"poster_path": "/q3mKnSkzp1doIsCye6ap4KIUAbu.jpg",
"original_language": "en",
"original_title": "The Secret Life of Pets 2",
"genre": "Comedy, Animation, Adventure",
"backdrop_path": "/5mFcjZ58f9Pqg5RNv493XlfgzIX.jpg",
"adult": false,
"overview": "The further adventures of Max the dog and his furry animal friends.",
"release_date": "2019-05-24"
},
{
"vote_count": 104,
"id": 471506,
"video": false,
"vote_average": 6.1,
"title": "Greta",
"popularity": 34.139,
"poster_path": "/9hBpFyJ3pGdupXbaC2L7nGvLMBn.jpg",
"original_language": "en",
"original_title": "Greta",
"genre": "Thriller, Drama, Mystery",
"backdrop_path": "/n67gpLtNFXqpGkM2ZdQoPLjTnI.jpg",
"adult": false,
"overview": "A young woman returns an elderly widow’s lost purse, leading to an unlikely relationship between the two — until the young woman discovers her elder might not be all that she seems.",
"release_date": "2019-02-28"
},
{
"vote_count": 0,
"id": 455957,
"video": false,
"vote_average": 0,
"title": "Domino",
"popularity": 31.812,
"poster_path": "/rrX1ojdd068aHlrGq5Khd92a3ba.jpg",
"original_language": "en",
"original_title": "Domino",
"genre": "Crime, Thriller",
"backdrop_path": "/1NGFwLyUo6YYLYD6jUaiWXgxh6n.jpg",
"adult": false,
"overview": "Seeking justice for his partner’s murder by an ISIS member, a Copenhagen police officer finds himself caught in a cat and mouse game with a duplicitous CIA agent who is using the killer as a pawn to trap other ISIS members.",
"release_date": "2019-05-31"
},
{
"vote_count": 45,
"id": 514439,
"video": false,
"vote_average": 6.5,
"title": "Breakthrough",
"popularity": 29.475,
"poster_path": "/t58dx7JIgchr9If5uxn3NmHaHoS.jpg",
"original_language": "en",
"original_title": "Breakthrough",
"genre": "Drama",
"backdrop_path": "/6jaNHf9ja84YG3KWMDK1nOnvGDg.jpg",
"adult": false,
"overview": "When he was 14, Smith drowned in Lake St. Louis and was dead for nearly an hour. According to reports at the time, CPR was performed 27 minutes to no avail. Then the youth's mother, Joyce Smith, entered the room, praying loudly. Suddenly, there was a pulse, and Smith came around.",
"release_date": "2019-04-11"
},
{
"vote_count": 98,
"id": 459992,
"video": false,
"vote_average": 6.8,
"title": "Long Shot",
"popularity": 28.19,
"poster_path": "/m2ttWZ8rMRwIMT7zA48Jo6mTkDS.jpg",
"original_language": "en",
"original_title": "Long Shot",
"genre": "Comedy, Romance",
"backdrop_path": "/88r25ghJzVYKq0vaOApqEOZsQlD.jpg",
"adult": false,
"overview": "When Fred Flarsky reunites with his first crush, one of the most influential women in the world, Charlotte Field, he charms her. As she prepares to make a run for the Presidency, Charlotte hires Fred as her speechwriter and sparks fly.",
"release_date": "2019-05-02"
},
{
"vote_count": 145,
"id": 376865,
"video": false,
"vote_average": 5.8,
"title": "High Life",
"popularity": 27.909,
"poster_path": "/wElOvH7H6sLElsTOLu1MY6oWRUx.jpg",
"original_language": "en",
"original_title": "High Life",
"genre": "Science Fiction, Drama, Mystery, Thriller",
"backdrop_path": "/6gHdAO1Lvk9bjzhY4hX3wVRkAhF.jpg",
"adult": false,
"overview": "Monte and his baby daughter are the last survivors of a damned and dangerous mission to the outer reaches of the solar system. They must now rely on each other to survive as they hurtle toward the oblivion of a black hole.",
"release_date": "2018-11-07"
}
]
class SearchItem extends React.Component {
render() {
return (
<div className="container">
<div className="image-container">
<img className="cover" src={`https://image.tmdb.org/t/p/w500/${this.props.image}`} />
</div>
<div className="info-container">
<p className="title">{this.props.title}</p>
<p>Genre: {this.props.genre}</p>
</div>
</div>
)
}
}
class List extends React.Component {
state = {
selectedStreamUrl: "",
searchInput: "",
showDeleteButton: false,
searchByGenre: false,
list: listData,
filteredList: listData,
filterBy: 'title',
}
//search
startSearch = (value) => {
const search = value.toLowerCase();
const searchKey = this.state.filterBy;
this.setState({
searchInput: value,
filteredList: this.state.list.filter(item => {
return item && item[searchKey].toLowerCase().includes(search)
}),
showDeleteButton: value ? true : false,
})
}
setAllLists = (allLists) => {
console.log("setAllLists")
console.log(this.state.searchByGenre)
this.setState({ filteredList: allLists })
//document.body.style.backgroundColor = "red";
}
removeInput = () => {
this.setState({
filterBy: 'title',
showDeleteButton: false,
searchInput: '',
}, () => this.startSearch(this.state.searchInput));
}
filterBy = (event) => {
const filter = event.target.value;
this.setState({
filterBy: filter
});
}
render() {
return (
<div class={style.list_container}>
<div>
<input value={this.state.searchInput} class={style.searchBar} type="text" id="searchField" placeholder={this.state.searchInput} onChange={(e) => this.startSearch(e.target.value)} ></input>
<select onChange={this.filterBy}>
<option selected={this.state.filterBy === 'title'} value="title">Title</option>
<option selected={this.state.filterBy === 'genre'} value="genre">Genre</option>
</select>
</div>
{
this.state.filterBy === 'genre' ?
<h1>ja</h1>
:
<h1>nee</h1>
}
{
this.state.showDeleteButton ?
<button class={style.deleteButton} onClick={() => this.removeInput()}>Remove</button>
: null
}
{
this.state.filteredList.map((item, index) => {
return <SearchItem image={item.poster_path} title={item.title} genre={item.genre} />
})
}
</div>
);
}
}
ReactDOM.render(<List />, document.getElementById('root'));
</script>
我正在开发一个组件,它应该能够:
按输入搜索 - 使用输入字段将在触发 onBlur 事件后调用一个函数。在 onBlur 事件之后,startSearch() 方法将 运行.
按 select 流派过滤 - 从其他组件,用户可以 select 流派列表中的流派。 onClick 事件后 startFilter() 方法将 运行.
好消息: 我得到了上面的 2 个函数。
坏消息: 以上 2 个功能不能正常工作。请看下面的代码。下面的 2 个调用有效,但前提是我将其中的 2 个注释掉。我尝试以各种方式调整 startSearch() 方法,但我一直走到一面大胖墙。
//////Searching works
//////this.filter(this.state.searchInput);
//Filtering works
this.startFilter(this.state.searchInput);
问题 如何让 filter/search 方法起作用?。不幸的是,简单地将它们放在 if/else 中并不是解决方案(请参阅代码中的注释)。
import { Component } from 'preact';
import listData from '../../assets/data.json';
import { Link } from 'preact-router/match';
import style from './style';
export default class List extends Component {
state = {
selectedStreamUrl: '',
searchInput: '',
showDeleteButton: false,
searchByGenre: false,
list: []
};
startFilter(input, filterByGenre) {
this.setState({
searchByGenre: true,
searchInput: input,
showDeleteButton: true
});
alert('startFilter ');
console.log(this.state.searchByGenre);
/////////---------------------------------
document.getElementById('searchField').disabled = false;
document.getElementById('searchField').value = input;
document.getElementById('searchField').focus();
// document.getElementById('searchField').blur()
document.getElementById('searchField').disabled = true;
console.log(input);
this.filter(input);
}
//search
startSearch(input) {
alert('startSearch ');
console.log(this.state.searchByGenre);
//komt uit render()
if (!this.state.searchByGenre) {
//check for input
this.setState({
searchInput: input.target.value,
showDeleteButton: true
});
//Searching works
//this.filter(this.state.searchInput);
//Filtering works
this.startFilter(this.state.searchInput);
// DOESNT WORK:
// if (this.state.searchInput != "") {
// this.filter(this.state.searchInput);
// } else {
// this.startFilter(this.state.searchInput);
// }
}
}
setAllLists(allLists) {
console.log('setAllLists');
console.log(this.state.searchByGenre);
this.setState({ list: allLists });
//document.body.style.backgroundColor = "red";
}
filter(input) {
let corresondingGenre = [];
let filteredLists = listData.filter(item1 => {
var test;
if (this.state.searchByGenre) {
alert('--this.state.searchByGenre');
//filterByGenre
//& item1.properties.genre == input
for (var i = 0; i < item1.properties.genre.length; i++) {
if (item1.properties.genre[i].includes(input)) {
corresondingGenre.push(item1);
test = item1.properties.genre[i].indexOf(input) !== -1;
return test;
}
this.setState({ list: corresondingGenre });
}
} else {
//searchByTitle
alert('--default');
test = item1.title.indexOf(input.charAt(0).toUpperCase()) !== -1;
}
return test;
});
console.log('filterdLists:');
console.log(filteredLists);
console.log('corresondingGenre:');
console.log(corresondingGenre);
//alert(JSON.stringify(filteredLists))
this.setState({ list: filteredLists });
}
removeInput() {
console.log('removeInput ');
console.log(this.state.searchByGenre);
this.setState({
searchInput: '',
showDeleteButton: false,
searchByGenre: false
});
document.getElementById('searchField').disabled = false;
this.filter(this.state.searchInput);
}
render() {
//alle 's komen in deze array, zodat ze gefilterd kunnen worden OBV title.
if (
this.state.list === undefined ||
(this.state.list.length == 0 && this.state.searchInput == '')
) {
//init list
console.log('render ');
console.log(this.state.searchByGenre);
this.filter(this.state.searchInput);
}
return (
<div class={style.list_container}>
<input
class={style.searchBar}
type="text"
id="searchField"
placeholder={this.state.searchInput}
onBlur={this.startSearch.bind(this)}
/>
{this.state.searchByGenre ? <h1>ja</h1> : <h1>nee</h1>}
{this.state.showDeleteButton ? (
<button class={style.deleteButton} onClick={() => this.removeInput()}>
Remove
</button>
) : null}
{this.state.list.map((item, index) => {
return (
<div>
<p>{item.title}</p>
</div>
);
})}
</div>
);
}
}
两种方式:
更改对构造函数的绑定(以及状态!)
constructor(props) {
super(props);
this.state = { searchByGenre: true }
this.startSeach = startSearch.bind(this);
}
startSearch(searchByGenre) {
//This is false after the call
console.log(this.state.searchByGenre)
}
render() {
return (
<input class={style.searchBar} type="text" id="searchField" placeholder="Search" value={this.state.searchInput} onBlur={this.startSearch} >
</input>
)
}
这样你就可以使用带参数的 startSearch
:
<input class={style.searchBar}
type="text"
id="searchField"
placeholder="Search"
value={this.state.searchInput}
onBlur={() => this.startSearch(this.state.searchByGenre)}
>
OR 你可以将 startSearch
更改为箭头函数,并从构造函数中删除绑定:
startSearch = (searchByGenre) => {
//This is false after the call
console.log(this.state.searchByGenre)
}
你可以看看为什么会这样here。
编辑:link讲的是typeScript,忽略它,关注箭头function/bind部分
你问的问题不清楚。但是请尽量明确您的组件以帮助调试问题。例如,使用构造函数并在其中声明您的组件状态。还要为那里的事件做 .bind 以使其简洁。
以下示例在触发 onBlur 事件时捕获状态变量为真,这与其初始状态值相同:
class List extends React.Component {
constructor(props) {
super(props);
this.state = {
searchByGenre: true
};
this.startSearch = this.startSearch.bind(this);
}
startSearch() {
// This value is true
console.log(this.state.searchByGenre)
}
render() {
return (
<input
type="text"
id="searchField"
placeholder="Search"
value={this.state.searchInput}
onBlur={this.startSearch}
/>
)
}
要使您的搜索和过滤器正常工作,您需要两个数组。
state = {
selectedStreamUrl: "",
searchInput: "",
showDeleteButton: false,
// searchByGenre: false, // removed, will use filter by from a list
// by default both arrays have the same value
list: listData, // holds the original data, doesn't change
filteredList: listData, // holds filterd list, filtered when the user types in input
// by default filter by title, will change when user, use a value from a list
filterBy: 'title',
}
您的搜索函数将使用 this.state.filterBy
值来过滤数组。无需创建多个函数。这为您提供了灵活性,因为您可以使用下拉列表中的多个值进行过滤,而无需更改代码。
startSearch = (value) => {
const search = value.toLowerCase();
// get filter value title, genre, etc
const searchKey = this.state.filterBy;
this.setState({
searchInput: value,
filteredList: this.state.list.filter(item => {
// filter base on key item['title'] or item['genre'] etc
return item && item[searchKey].toLowerCase().includes(search)
}),
showDeleteButton: !!value,
})
}
删除输入功能
removeInput = () => {
this.setState({
filterBy: 'title',
showDeleteButton: false,
searchInput: '',
}, () => this.startSearch(this.state.searchInput));
}
我看到你做了很多 document.getElementById("searchField").disabled = false;
。不要直接操作 dom,让 React 为您管理。
查看下面的演示
h1, p {
font-family: Lato;
}
.container {
display: flex;
flex-direction: row;
border-bottom-style: solid;
margin-bottom: 5px;
}
.image-container {
flex-grow: 0;
}
.info-container {
flex-grow: 1;
margin-left: 10px
}
.title {
margin-top: 0;
}
.cover {
width: 60px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.0/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.21.1/babel.min.js"></script>
<div id="root"></div>
<script type="text/babel">
const style = {};
const listData = [
{
"vote_count": 806,
"id": 420817,
"video": false,
"vote_average": 7.2,
"title": "Aladdin",
"popularity": 476.676,
"poster_path": "/3iYQTLGoy7QnjcUYRJy4YrAgGvp.jpg",
"original_language": "en",
"original_title": "Aladdin",
"genre": "Adventure",
"backdrop_path": "/v4yVTbbl8dE1UP2dWu5CLyaXOku.jpg",
"adult": false,
"overview": "A kindhearted street urchin named Aladdin embarks on a magical adventure after finding a lamp that releases a wisecracking genie while a power-hungry Grand Vizier vies for the same lamp that has the power to make their deepest wishes come true.",
"release_date": "2019-05-22"
},
{
"vote_count": 70,
"id": 373571,
"video": false,
"vote_average": 6.4,
"title": "Godzilla: King of the Monsters",
"popularity": 143.161,
"poster_path": "/pU3bnutJU91u3b4IeRPQTOP8jhV.jpg",
"original_language": "en",
"original_title": "Godzilla: King of the Monsters",
"genre": "Action",
"backdrop_path": "/mzRJpkWPjXdXak0WCc8ZxVH4hug.jpg",
"adult": false,
"overview": "The new story follows the heroic efforts of the crypto-zoological agency Monarch as its members face off against a battery of god-sized monsters, including the mighty Godzilla, who collides with Mothra, Rodan, and his ultimate nemesis, the three-headed King Ghidorah. When these ancient super-species—thought to be mere myths—rise again, they all vie for supremacy, leaving humanity’s very existence hanging in the balance.",
"release_date": "2019-05-29"
},
{
"vote_count": 984,
"id": 447404,
"video": false,
"vote_average": 7,
"title": "Pokémon Detective Pikachu",
"popularity": 109.979,
"poster_path": "/wgQ7APnFpf1TuviKHXeEe3KnsTV.jpg",
"original_language": "en",
"original_title": "Pokémon Detective Pikachu",
"genre": "Mystery",
"backdrop_path": "/nDP33LmQwNsnPv29GQazz59HjJI.jpg",
"adult": false,
"overview": "In a world where people collect pocket-size monsters (Pokémon) to do battle, a boy comes across an intelligent monster who seeks to be a detective.",
"release_date": "2019-05-03"
},
{
"vote_count": 136,
"id": 531309,
"video": false,
"vote_average": 5.6,
"title": "Brightburn",
"popularity": 108.875,
"poster_path": "/sJWwkYc9ajwnPRSkqj8Aue5JbKz.jpg",
"original_language": "en",
"original_title": "Brightburn",
"genre": "Horror",
"backdrop_path": "/uHEI6v8ApQusjbaRZ8o7WcLYeWb.jpg",
"adult": false,
"overview": "What if a child from another world crash-landed on Earth, but instead of becoming a hero to mankind, he proved to be something far more sinister?",
"release_date": "2019-05-09"
},
{
"vote_count": 570,
"id": 527641,
"video": false,
"vote_average": 8.1,
"title": "Five Feet Apart",
"popularity": 72.32,
"poster_path": "/kreTuJBkUjVWePRfhHZuYfhNE1T.jpg",
"original_language": "en",
"original_title": "Five Feet Apart",
"genre": "Romance",
"backdrop_path": "/27ZkYMWynuK2qiDP6awc3MsCaOs.jpg",
"adult": false,
"overview": "Seventeen-year-old Stella spends most of her time in the hospital as a cystic fibrosis patient. Her life is full of routines, boundaries and self-control -- all of which get put to the test when she meets Will, an impossibly charming teen who has the same illness. There's an instant flirtation, though restrictions dictate that they must maintain a safe distance between them. As their connection intensifies, so does the temptation to throw the rules out the window and embrace that attraction.",
"release_date": "2019-03-15"
},
{
"vote_count": 162,
"id": 449562,
"video": false,
"vote_average": 6.1,
"title": "The Hustle",
"popularity": 71.346,
"poster_path": "/qibqW5Dnvqp4hcEnoTARbQgxwJy.jpg",
"original_language": "en",
"original_title": "The Hustle",
"genre": "Comedy",
"backdrop_path": "/s6awXOxTKYQLSktiIJfI3969dZH.jpg",
"adult": false,
"overview": "Two female scam artists, one low rent and the other high class, compete to swindle a naïve tech prodigy out of his fortune. A remake of the 1988 comedy \"Dirty Rotten Scoundrels.\"",
"release_date": "2019-05-09"
},
{
"vote_count": 88,
"id": 504608,
"video": false,
"vote_average": 7.7,
"title": "Rocketman",
"popularity": 66.812,
"poster_path": "/f4FF18ia7yTvHf2izNrHqBmgH8U.jpg",
"original_language": "en",
"original_title": "Rocketman",
"genre": "Drama",
"backdrop_path": "/oAr5bgf49vxga9etWoQpAeRMvhp.jpg",
"adult": false,
"overview": "The story of Elton John's life, from his years as a prodigy at the Royal Academy of Music through his influential and enduring musical partnership with Bernie Taupin.",
"release_date": "2019-05-22"
},
{
"vote_count": 124,
"id": 505600,
"video": false,
"vote_average": 7,
"title": "Booksmart",
"popularity": 57.801,
"poster_path": "/Awyg5IdELQV3sBoErhJ9QVcX8TA.jpg",
"original_language": "en",
"original_title": "Booksmart",
"genre": "Drama, Comedy",
"backdrop_path": "/wcAqndL2MkIjPrCrYeuE794weNE.jpg",
"adult": false,
"overview": "Two academic teenage superstars realize, on the eve of their high school graduation, that they should have worked less and played more. Determined to never fall short of their peers, the girls set out on a mission to cram four years of fun into one night.",
"release_date": "2019-05-24"
},
{
"vote_count": 10,
"id": 502416,
"video": false,
"vote_average": 4.8,
"title": "Ma",
"popularity": 55.328,
"poster_path": "/6n7ASmQ1wY2cxTubFFGlcvPpyk7.jpg",
"original_language": "en",
"original_title": "Ma",
"genre": "Comedy, Horror",
"backdrop_path": "/mBOv5YrX5QGr5CusK0PKSHuxOt9.jpg",
"adult": false,
"overview": "Sue Ann is a loner who keeps to herself in her quiet Ohio town. One day, she is asked by Maggie, a new teenager in town, to buy some booze for her and her friends, and Sue Ann sees the chance to make some unsuspecting, if younger, friends of her own. She offers the kids the chance to avoid drinking and driving by hanging out in the basement of her home. But there are some house rules: One of the kids has to stay sober. Don’t curse. Never go upstairs. And call her “Ma.” But as Ma’s hospitality starts to curdle into obsession, what began as a teenage dream turns into a terrorizing nightmare, and Ma’s place goes from the best place in town to the worst place on earth.",
"release_date": "2019-05-29"
},
{
"vote_count": 88,
"id": 535581,
"video": false,
"vote_average": 5.9,
"title": "The Dead Don't Die",
"popularity": 52.857,
"poster_path": "/ycMSfP8KRFsVUWfbSxSFpD97QfD.jpg",
"original_language": "en",
"original_title": "The Dead Don't Die",
"genre": "Comedy, Horror",
"backdrop_path": "/cXyfAViYly0Lk2CVpEKgYbt9wKQ.jpg",
"adult": false,
"overview": "In a small peaceful town, zombies suddenly rise to terrorize the town. Now three bespectacled police officers and a strange Scottish morgue expert must band together to defeat the undead.",
"release_date": "2019-05-15"
},
{
"vote_count": 0,
"id": 320288,
"video": false,
"vote_average": 0,
"title": "Dark Phoenix",
"popularity": 52.433,
"poster_path": "/kZv92eTc0Gg3mKxqjjDAM73z9cy.jpg",
"original_language": "en",
"original_title": "Dark Phoenix",
"genre": "Action, Science Fiction",
"backdrop_path": "/A2oPzeKjSpCovYLqoDDXFbrJgyS.jpg",
"adult": false,
"overview": "The X-Men face their most formidable and powerful foe when one of their own, Jean Grey, starts to spiral out of control. During a rescue mission in outer space, Jean is nearly killed when she's hit by a mysterious cosmic force. Once she returns home, this force not only makes her infinitely more powerful, but far more unstable. The X-Men must now band together to save her soul and battle aliens that want to use Grey's new abilities to rule the galaxy.",
"release_date": "2019-06-05"
},
{
"vote_count": 10,
"id": 496243,
"video": false,
"vote_average": 9.4,
"title": "Parasite",
"popularity": 46.835,
"poster_path": "/7IiTTgloJzvGI1TAYymCfbfl3vT.jpg",
"original_language": "ko",
"original_title": "기생충",
"genre": "Drama, Comedy",
"backdrop_path": "/ny5aCtglk2kceGAuAdiyqbhBBAf.jpg",
"adult": false,
"overview": "All unemployed, Ki-taek's family takes peculiar interest in the wealthy and glamorous Parks for their livelihood until they get entangled in an unexpected incident.",
"release_date": "2019-05-30"
},
{
"vote_count": 71,
"id": 526050,
"video": false,
"vote_average": 6.2,
"title": "Little",
"popularity": 43.334,
"poster_path": "/4MDB6jJl3U7xK1Gw64zIqt9pQA4.jpg",
"original_language": "en",
"original_title": "Little",
"genre": "Comedy, Fantasy",
"backdrop_path": "/tmM78qRhpg0i2Cky8Q8hXKASOXY.jpg",
"adult": false,
"overview": "A woman receives the chance to relive the life of her younger self, at a point in her life when the pressures of adulthood become too much for her to bear.",
"release_date": "2019-04-04"
},
{
"vote_count": 1181,
"id": 329996,
"video": false,
"vote_average": 6.6,
"title": "Dumbo",
"popularity": 39.349,
"poster_path": "/279PwJAcelI4VuBtdzrZASqDPQr.jpg",
"original_language": "en",
"original_title": "Dumbo",
"genre": "Adventure, Animation, Fantasy",
"backdrop_path": "/5tFt6iuGnKapHl5tw0X0cKcnuVo.jpg",
"adult": false,
"overview": "A young elephant, whose oversized ears enable him to fly, helps save a struggling circus, but when the circus plans a new venture, Dumbo and his friends discover dark secrets beneath its shiny veneer.",
"release_date": "2019-03-27"
},
{
"vote_count": 19,
"id": 412117,
"video": false,
"vote_average": 6.5,
"title": "The Secret Life of Pets 2",
"popularity": 38.485,
"poster_path": "/q3mKnSkzp1doIsCye6ap4KIUAbu.jpg",
"original_language": "en",
"original_title": "The Secret Life of Pets 2",
"genre": "Comedy, Animation, Adventure",
"backdrop_path": "/5mFcjZ58f9Pqg5RNv493XlfgzIX.jpg",
"adult": false,
"overview": "The further adventures of Max the dog and his furry animal friends.",
"release_date": "2019-05-24"
},
{
"vote_count": 104,
"id": 471506,
"video": false,
"vote_average": 6.1,
"title": "Greta",
"popularity": 34.139,
"poster_path": "/9hBpFyJ3pGdupXbaC2L7nGvLMBn.jpg",
"original_language": "en",
"original_title": "Greta",
"genre": "Thriller, Drama, Mystery",
"backdrop_path": "/n67gpLtNFXqpGkM2ZdQoPLjTnI.jpg",
"adult": false,
"overview": "A young woman returns an elderly widow’s lost purse, leading to an unlikely relationship between the two — until the young woman discovers her elder might not be all that she seems.",
"release_date": "2019-02-28"
},
{
"vote_count": 0,
"id": 455957,
"video": false,
"vote_average": 0,
"title": "Domino",
"popularity": 31.812,
"poster_path": "/rrX1ojdd068aHlrGq5Khd92a3ba.jpg",
"original_language": "en",
"original_title": "Domino",
"genre": "Crime, Thriller",
"backdrop_path": "/1NGFwLyUo6YYLYD6jUaiWXgxh6n.jpg",
"adult": false,
"overview": "Seeking justice for his partner’s murder by an ISIS member, a Copenhagen police officer finds himself caught in a cat and mouse game with a duplicitous CIA agent who is using the killer as a pawn to trap other ISIS members.",
"release_date": "2019-05-31"
},
{
"vote_count": 45,
"id": 514439,
"video": false,
"vote_average": 6.5,
"title": "Breakthrough",
"popularity": 29.475,
"poster_path": "/t58dx7JIgchr9If5uxn3NmHaHoS.jpg",
"original_language": "en",
"original_title": "Breakthrough",
"genre": "Drama",
"backdrop_path": "/6jaNHf9ja84YG3KWMDK1nOnvGDg.jpg",
"adult": false,
"overview": "When he was 14, Smith drowned in Lake St. Louis and was dead for nearly an hour. According to reports at the time, CPR was performed 27 minutes to no avail. Then the youth's mother, Joyce Smith, entered the room, praying loudly. Suddenly, there was a pulse, and Smith came around.",
"release_date": "2019-04-11"
},
{
"vote_count": 98,
"id": 459992,
"video": false,
"vote_average": 6.8,
"title": "Long Shot",
"popularity": 28.19,
"poster_path": "/m2ttWZ8rMRwIMT7zA48Jo6mTkDS.jpg",
"original_language": "en",
"original_title": "Long Shot",
"genre": "Comedy, Romance",
"backdrop_path": "/88r25ghJzVYKq0vaOApqEOZsQlD.jpg",
"adult": false,
"overview": "When Fred Flarsky reunites with his first crush, one of the most influential women in the world, Charlotte Field, he charms her. As she prepares to make a run for the Presidency, Charlotte hires Fred as her speechwriter and sparks fly.",
"release_date": "2019-05-02"
},
{
"vote_count": 145,
"id": 376865,
"video": false,
"vote_average": 5.8,
"title": "High Life",
"popularity": 27.909,
"poster_path": "/wElOvH7H6sLElsTOLu1MY6oWRUx.jpg",
"original_language": "en",
"original_title": "High Life",
"genre": "Science Fiction, Drama, Mystery, Thriller",
"backdrop_path": "/6gHdAO1Lvk9bjzhY4hX3wVRkAhF.jpg",
"adult": false,
"overview": "Monte and his baby daughter are the last survivors of a damned and dangerous mission to the outer reaches of the solar system. They must now rely on each other to survive as they hurtle toward the oblivion of a black hole.",
"release_date": "2018-11-07"
}
]
class SearchItem extends React.Component {
render() {
return (
<div className="container">
<div className="image-container">
<img className="cover" src={`https://image.tmdb.org/t/p/w500/${this.props.image}`} />
</div>
<div className="info-container">
<p className="title">{this.props.title}</p>
<p>Genre: {this.props.genre}</p>
</div>
</div>
)
}
}
class List extends React.Component {
state = {
selectedStreamUrl: "",
searchInput: "",
showDeleteButton: false,
searchByGenre: false,
list: listData,
filteredList: listData,
filterBy: 'title',
}
//search
startSearch = (value) => {
const search = value.toLowerCase();
const searchKey = this.state.filterBy;
this.setState({
searchInput: value,
filteredList: this.state.list.filter(item => {
return item && item[searchKey].toLowerCase().includes(search)
}),
showDeleteButton: value ? true : false,
})
}
setAllLists = (allLists) => {
console.log("setAllLists")
console.log(this.state.searchByGenre)
this.setState({ filteredList: allLists })
//document.body.style.backgroundColor = "red";
}
removeInput = () => {
this.setState({
filterBy: 'title',
showDeleteButton: false,
searchInput: '',
}, () => this.startSearch(this.state.searchInput));
}
filterBy = (event) => {
const filter = event.target.value;
this.setState({
filterBy: filter
});
}
render() {
return (
<div class={style.list_container}>
<div>
<input value={this.state.searchInput} class={style.searchBar} type="text" id="searchField" placeholder={this.state.searchInput} onChange={(e) => this.startSearch(e.target.value)} ></input>
<select onChange={this.filterBy}>
<option selected={this.state.filterBy === 'title'} value="title">Title</option>
<option selected={this.state.filterBy === 'genre'} value="genre">Genre</option>
</select>
</div>
{
this.state.filterBy === 'genre' ?
<h1>ja</h1>
:
<h1>nee</h1>
}
{
this.state.showDeleteButton ?
<button class={style.deleteButton} onClick={() => this.removeInput()}>Remove</button>
: null
}
{
this.state.filteredList.map((item, index) => {
return <SearchItem image={item.poster_path} title={item.title} genre={item.genre} />
})
}
</div>
);
}
}
ReactDOM.render(<List />, document.getElementById('root'));
</script>