#javascript #reactjs
#javascript #reactjs
Вопрос:
Я пытаюсь создать список фильтров, который фильтрует список по введенному вводу. Но не знаю, почему оператор if не работает.
Вот функция, которую я написал: `
filterList (event) {
var updatedList = this.props.array;
var filterText = this.state.text;
updatedList = updatedList.filter(function(item){
console.log(filterText);
if(item.name === filterText){
console.log('check', item.name);
}
});
Может ли кто-нибудь помочь мне в этом, вот ссылка на мой codepen: ССЫЛКА
Комментарии:
1. Поскольку вы устанавливаете локальную переменную в отфильтрованный массив, вы не возвращаете ее, вы не обновляете состояние, вы фильтруете его, а затем выбрасываете.
Ответ №1:
Вашему фильтру необходимо обновить массив в состоянии компонента, чтобы принудительно выполнить повторную визуализацию. Вы не обновляете реквизиты для принудительного повторного рендеринга, реквизиты предназначены скорее для исходных данных или согласованных данных, которые можно обновлять с верхнего уровня.
Измените функцию handle, чтобы передать текст функции FilterList и вернуть результат
handleChange(event) {
var array = this.filterList(event.target.value);
this.setState({ text: event.target.value, array: array });
},
filterList (filterText) {
var updatedList = this.props.array;
return updatedList.filter(function(item){
return item.name === filterText;
});
}
Обновите getInitialState для использования реквизитов:
getInitialState() {
return { text:'', array: this.props.array};
}
Затем используйте состояние вместо реквизита в вашем рендеринге:
var arrayComponents = this.state.array.map(function(photo) {
return <li className="photo photo-name">{photo.name} <img className="photo" src={photo.link}/></li>;
})
Комментарии:
1. Спасибо, это работает, может быть, у вас есть решение для фильтрации отдельных букв? Теперь он фильтрует только тогда, когда целое имя совпадает с вводом
2. Конечно. Извините за поздний ответ. Вам просто нужно изменить сравнение equals. Если вы хотите, чтобы текст основывался на том, с чего он начинается. Таким
Phot
образом, соответствует, ноoto
не использует обычное повторное выражение.return new RegExp('^' filterText).test(item.name)
. Если вы просто хотите сопоставить, содержится ли текст, можете сделать :return item.name.indexOf(filterText) !== -1
.
Ответ №2:
Во-первых, когда я запускаю ваш пример codepen, я не вижу никаких ошибок, указывающих на то, что this.state.text
это не определено. Он ничего не фильтрует, но отображает значение this.state.text
. Итак, проблема не совсем в том, что предполагает ваш вопрос…
Итак, как мы можем фильтровать эту вещь? По сути, идея компонентов ReactJS заключается в том, что все, что связано с текущим состоянием вашего компонента, должно быть this.state
включено , и любые решения о том, что отображать на основе этого состояния, должны быть в render
методе. И имейте в виду, что каждый раз, когда вы меняете состояние с помощью setState
метода, это вызовет повторный рендеринг вашего компонента.
Имея это в виду, я бы настроил все следующим образом:
-
ваш компонент получает список фотографий через
array
prop (я бы, наверное, назвал это как-то по-другому, поскольку он не очень описательный и очень близок к зарезервированному слову в Javascript) -
состояние компонента имеет одно значение:
text
(опять же, не очень описательное) -
компонент имеет
handleChange
обработчик для входного элемента. Я бы подключил это кonChange
обработчику для элемента ввода — не волнуйтесь, он будет вызываться каждый раз, когда изменяется значение во входном элементе. Это должен быть единственный обработчик событий для элемента ввода, и все, что он должен сделать, это вызватьthis.setState({ text: event.target.value });
-
выполните фильтрацию списка в методе render. Ключевым моментом здесь является то, что вам не нужно сохранять отфильтрованный список ваших фотографий — все, что вы делаете с ним, это его рендеринг, поэтому делайте это только тогда, когда вам нужно (или, скорее, когда React считает, что вам нужно, и вызывает
render
метод). Итак, ваш метод визуализации будет выглядеть примерно так:render() { var myFilteredList = this.props.array.filter(function(item){ console.log(filterText); if(item.name === filterText){ console.log('check', item.name); return true; } return false; }); var arrayComponents = myFilteredList.map(function(photo) { return <li className="photo photo-name">{photo.name} <img className="photo" src={photo.link}/></li>; }); return ( <div> <h1>Hello, {this.props.name}</h1> <p>{this.state.text}</p> <input type="text" onKeyUp={this.handleChange} /> <ul> {arrayComponents} </ul> </div> ); }
Вот и все. Это имеет несколько преимуществ:
-
это упрощает задачу — не поддерживайте какое-либо состояние для компонента вне
this.state
и, если оно вам нужно только для рендеринга, не поддерживайте его вообще. -
это делает ваш код более чистым — как я к этому подошел, у вашего компонента есть только два метода:
handleChange
иrender
-
он (должен быть) более производительным — React довольно хорошо решает, когда отображать на основе изменений состояния, и, как правило, лучше, когда компоненты имеют минимальное состояние. (Я говорю «должно быть» просто потому, что я его вообще не тестировал).