Я мутирую? Если да, какие решения доступны?
У меня есть простой компонент, который создает список отчетов из массива объектов, я пытаюсь добавить функцию фильтрации и сортировки (которая работает - до некоторой степени), функция сортировки работает, но я боюсь, что меняю состояние, несмотря на попытку скопировать исходное состояние в новый массив.
Мой фильтр работает в течение первого раза, но тогда он не будет фильтровать другие результаты, потому что состояние было изменено, или потому что я не могу фильтровать через начальное состояние? Это меня смущало в течение многих часов, любая помощь очень ценится.
Спасибо большое
constructor(props) {
super(props);
this.state = {
reports: props.data
};
this.handleSortBy = this.handleSortBy.bind(this);
this.handleFilterType = this.handleFilterType.bind(this);
}
handleSortBy(event) {
const copy = [...this.state.reports];
if (event.target.value === 'A-Z') {
return this.setState({
reports: copy.sort((a, b) => a.name.localeCompare(b.name))
});
}
if (event.target.value === 'Z-A') {
this.setState({
reports: copy
.sort((a, b) => a.name.localeCompare(b.name))
.reverse()
});
}
}
handleFilterType(event) {
this.setState({
reports: this.state.reports.filter(item => {
return item.type === event.target.value;
})
});
}
Заранее спасибо:)
2 ответа
Один простой способ сделать это в зависимости от вашего варианта использования - это заменить this.state.reports
с this.props.data
в ваших двух функциях обновления. (Хотя, если вы сделаете это таким образом, вы не сможете применить сортировку и фильтр одновременно)
Но я согласен с ModestLeech, что лучше хранить фильтр в состоянии. Для этого измените код фильтра на что-то вроде:
handleFilterType(event) {
this.setState({
filter: event.target.value;
})
});
}
И в вашем методе рендеринга, если вы используете карту, вы можете изменить карту на this.state.reports.filter(item => (this.state.filter===undefined || item.type===this.state.filter)).map(...)
,
РЕДАКТИРОВАТЬ:
Есть два типа мутаций, о которых вам нужно беспокоиться с помощью React.
Один не мутирует ваш реквизит (то есть мутирует состояние, которое ваш компонент не контролирует). Поскольку Javascript передает массивы и объекты по ссылке, если бы вы sort
на this.props.data
это фактически изменило бы массив, который существует в родительском компоненте вашего компонента (или дедушке, или где бы он ни был определен). Хорошей новостью является то, что ваш оригинальный код уже избежал этого - возможно, случайно. handleSortBy
сделал копию массива перед тем, как изменить его, и handleFilterType
использования Array.prototype.filter
, который создает новый массив.
Вторая мутация, о которой вам нужно беспокоиться - это изменение локального состояния без использования setState
, призвание this.state.reports.sort(...)
в render
изменит локальное состояние, но React не узнает и не выполнит повторную визуализацию. Это не проблема, поскольку вы сортируете прямо перед тем, как вам это нужно, но прямое изменение состояния опасно, потому что это может привести к ошибкам, когда вы, как разработчик, думаете, что что-то должно или не должно измениться при определенных условиях, но реальность другая,
Ваша первоначальная проблема с filter
не имеет ничего общего со случайной мутацией. Проблема заключалась в том, что, позвонив this.setState
первый раз с фильтром переписал this.state.reports
и не было никакого способа вернуть его. Также была проблема, что если this.props.data
При изменении родительского элемента новые отчеты никогда не будут отображаться в этом компоненте, поскольку вы читаете реквизиты только при первом создании компонента.
Рекомендованный способ React - не хранить что-либо в состоянии, исходящем от подпорки, если только вы не используете подпорку для установки начального состояния и все будущие обновления будут поступать изнутри компонента. Но если предположить, что этот компонент в конечном итоге не владеет списком отчетов, в конечном итоге было бы проще сделать копию this.props.data
в render
и примените свой сортировку и фильтр к нему. Затем, если что-либо будет добавлено или удалено выше в дереве компонентов, вам не нужно будет писать какую-либо специальную логику для обновления локального состояния этого компонента.
Я думаю, что проблема в том, что каждый раз, когда вы фильтруете, вы удаляете элементы из state.reports
и никогда не получит их от props.data
,
Вместо этого вы должны восстановить state.reports
от props.data
каждый раз, когда вы фильтруете / сортируете.
Или лучшим способом, IMO, было бы сохранить настройки фильтрации / сортировки в state
и выполнить фильтрацию / сортировку props.data
в render
на основании текущих настроек.