#javascript #reactjs #react-hooks
#javascript #reactjs #реагировать-крючки
Вопрос:
Я пытаюсь отфильтровать этот массив при изменении входного «фильтра», но когда я пытаюсь ввести, он хорошо фильтрует, но переопределяет исходный список. Итак, как я могу отфильтровать список при вводе и вернуться к исходному списку при удалении значения фильтра?
const [persons, setPersons] = useState([
{ name: 'Arto Hellas', number: '040-123456' },
{ name: 'Ada Lovelace', number: '39-44-5323523' },
{ name: 'Dan Abramov', number: '12-43-234345' },
{ name: 'Mary Poppendieck', number: '39-23-6423122' }
])
const [filter, setFilter] = useState('')
const handleFilter = e => {
setFilter(e.target.value)
const personsFiltered = persons.filter(({ name }) => name.includes(filter))
if (personsFiltered.length > 0)
setPersons(personsFiltered)
}
return (
<div>
<input value={filter} onChange={handleFilter} />
{persons.map((person, index) => <p key={index}>{person.name} {person.number}</p>)}
</div>
)
Комментарии:
1. Где ваш код рендеринга для лиц? Вы могли бы более легко сделать это, выполнив фильтр в функции рендеринга, а не изменяя список
2. Не храните отфильтрованный массив в состоянии, которое может быть вычислено из того, что у вас уже есть в состоянии. Если вы обнаружите, что фильтрация по требованию является узким местом в производительности, используйте
useMemo
для запоминания результата.3. У вас должна быть копия оригинала для выполнения фильтрации. когда вам это нужно, просто сбросьте его с оригинальным.
4. Спасибо за обновление вашего кода — пожалуйста, смотрите Мой ответ о том, как добиться этого как часть кода, который вы уже визуализируете.
Ответ №1:
Вы должны быть в состоянии достичь желаемого, отфильтровав свои результаты как часть рендеринга. Вы обновляете свое filter
состояние, поэтому повторный рендеринг должен запускаться, как и ожидалось, при событии:
РЕДАКТИРОВАТЬ: я вижу, что вы обновили свой вопрос своим кодом рендеринга. Вы должны иметь возможность просто применить filter
функцию к тому, что у вас уже есть:
{persons.filter(({ name }) => name.includes(filter)).map((person, index) => <p key={index}>{person.name} {person.number}</p>)}
Ответ №2:
Вы должны поддерживать дополнительное состояние для отфильтрованных значений.
Просто используй другой useState
const [persons, setPersons] = useState([
{ name: 'Arto Hellas', number: '040-123456' },
{ name: 'Ada Lovelace', number: '39-44-5323523' },
{ name: 'Dan Abramov', number: '12-43-234345' },
{ name: 'Mary Poppendieck', number: '39-23-6423122' }
])
// use additional state here
const [personsFiltered, setPersonsFiltered] = useState(persons);
const [filter, setFilter] = useState('')
const handleFilter = e => {
setFilter(e.target.value)
const personsFiltered = persons.filter(({ name }) => name.includes(filter))
if (personsFiltered.length > 0)
// set the additional state here
setPersonsFiltered(personsFiltered)
}
return(<input value={filter} onChange={handleFilter} />)
Комментарии:
1. Использование другого состояния для этого, на мой взгляд, не требуется — оно просто оставляет другое состояние для управления и быть в курсе, когда мы можем выполнять логику фильтрации как часть рендеринга.
2. у вас все еще должен быть где-то исходный список, и каждое изменение ввода должно сверяться с исходным списком, а не с уже отфильтрованным списком. обычно этот исходный список поступает из реквизитов, вместо того, чтобы определять его внутри компонента
3. Однако вы можете выполнить фильтрацию как часть рендеринга и не беспокоиться ни об одной из этих проблем.
4. В некоторых случаях это верно. Все зависит от того, выполняете ли вы другие действия с отфильтрованным массивом перед рендерингом компонента.