Я мутирую?Если да, какие решения доступны? - PullRequest
0 голосов
/ 11 февраля 2019

У меня есть простой компонент, который создает список отчетов из массива объектов, я пытаюсь добавить функцию фильтрации и сортировки (которая работает - до некоторой степени), функция сортировки работает, но, боюсь, яменяю состояние несмотря на попытку скопировать исходное состояние в новый массив.

Мой фильтр работает в первый раз, но тогда он не будет фильтровать другие результаты, потому что состояние было изменено, или потому что я не могу отфильтровать исходное состояние?Это меня смущало в течение многих часов, любая помощь очень ценится.

Большое спасибо

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 ]

0 голосов
/ 11 февраля 2019

Один простой способ сделать это в зависимости от вашего варианта использования - заменить 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 и применить к ней сортировку и фильтр.Затем, если что-либо будет добавлено или удалено выше в дереве компонентов, вам не нужно будет писать какую-либо специальную логику для обновления локального состояния этого компонента.

0 голосов
/ 11 февраля 2019

Я думаю, что проблема заключается в том, что каждый раз, когда вы фильтруете, вы удаляете элементы из state.reports и никогда не получаете их обратно из props.data.

Вместо этого вы должны восстановить state.reports из props.dataкаждый раз, когда вы фильтруете / сортируете.

Или лучшим способом, IMO, было бы сохранить настройки фильтрации / сортировки в state и выполнить фильтрацию / сортировку props.data в render на основетекущие настройки.

...