React + redux фильтры

Всем привет, у меня задача сделать фильтр по полям имя,фамилия, e-mail. Встал такой вопрос, а как это сделать в redux-сом?

Для каждого фильтра я сделал компонент в реакте, такого вида :

import React from 'react'
import { Component } from 'react'
import { connect } from 'react-redux'

class SearchEmail extends Component {

    constructor(props) {
        super(props);
        this.searchInTheEmail = this.searchInTheEmail.bind(this);
    }

    searchInTheEmail(){
        this.props.searchEmail(this.emailUser.value, 2);
    }


    render() {
        return (
            <div className="row campid">
                <div className="col-md-6">
                    <div className="dropdown">
                        <input className="btn btn-default dropdown-toggle" type="text" placeholder="Поиск по E-mail" ref = {(input) => { this.emailUser = input; }}
                               onKeyUp = {_.throttle(this.searchInTheEmail.bind(this), 2000, {leading: false})}
                        />
                    </div>
                </div>
                <div className="col-md-6"></div>
            </div>
        )
    }}export default connect(
    dispatch => ({
        searchEmail : (email, index) => {
            dispatch({ type : 'SEARCH' , email : email, index : index})
        }
    }))(SearchEmail)

Все это уходит в редьюсер

    export default function search(state = 0, action) {
    switch(action.type) {
        case 'SEARCH' :
            return Object.assign({}, state , { login : action.login, email : action.email, index : action.index });
    }
    return state;
}

а в главном компоненте все отрендеривается так:

     class TableUsers extends Component {

    componentWillMount() {
        this.ajax()
    }

    constructor(props) {
        super(props)
        this.ajax = this.ajax.bind(this);
    }

    ajax(){

         var filterUserLogin = '';
         var filterUserEmail = '';
         var filterActivUser = '';
         var filterPagination = '';

        var search = this.props.search;

        if(search){
            switch(search.index){
                case 1 : var filterUserLogin = search.login; break;
                case 2 : var filterUserEmail = search.email; break;
            }
            this.props.clearSearch('' , 0);
        }

        var _self = this;
        $('body').faLoading();

        $.ajax({
            dataType : 'json',
            url      : '/AdminGroupHead/getDataUsers',
            data     : {
                filterUserLogin : filterUserLogin,
                filterUserEmail : filterUserEmail,
                // filterActivUser : filterActivUser,
                // filterPagination : filterPagination
            },
            success : function (data) {
                _self.props.getDataUsers(data);
                $('body').faLoading(false);
            }
        });
    }

    render() {
        var element = [];
        const data = this.props.dataUser;
        const search = this.props.search;

        if(data !== undefined){
            if(search !== 0){
                if(search.index !== 0){
                    this.ajax();
                }
            }
            _.each(data.data.dataUser, function (i, k) {
                element[i.id] =  <tr key={k}>
                                <td>{i.id}</td>
                                <th>ID</th>
                                <th>Вкл.</th>
                                <th className = 'loginWitch'>Логин</th>
                                <th className = 'emailWitch'>E-mail</th>
                                <th>Доступ</th>
                                <th>Компания</th>
                                <th>Города</th>
                                <th>Регионы</th>
                                <th>Клиенты</th>
                                <th>Доступы</th>
                                <th>Роль</th>
                            </tr>
            }, this)
        }

        return (
            <div>
                <div className="panel panel-default panel-large-table">
                    <div className="panel-heading">
                        <a href="">
                            <span className="mc-icon mc_icon_refresh" title="Обновить данные таблицы"></span>
                        </a>
                        <a id="ClassAddUserList">
                            <span className="mc-icon mc_icon_plus" title="Добавить пользователей" data-toggle="modal" ></span>
                        </a>
                    </div>
                </div>
                <div className = "table-responsive" >
                    <table className="table table-bordered">
                        <thead>
                        <tr>
                            <th>*</th>
                            <th>ID</th>
                            <th>Вкл.</th>
                            <th className = 'loginWitch'>Логин</th>
                            <th className = 'emailWitch'>E-mail</th>
                            <th>Доступ</th>
                            <th>Компания</th>
                            <th>Города</th>
                            <th>Регионы</th>
                            <th>Клиенты</th>
                            <th>Доступы</th>
                            <th>Роль</th>
                        </tr>
                        </thead>
                        <tbody className = "tbodyTableGh">
                        {element}
                        </tbody>
                    </table>
                </div>
            </div>
        )
    }
}

    export default connect(
    state => ({
        dataUser : state.getData.users,
        search   : state.search
    }),
    dispatch => ({
        getDataUsers : (data) => {
            dispatch({ type : 'GET_DATA_USERS' , data : data}) // получение первоначальных данных
        },
        clearSearch : (data, index ) => {
            dispatch({ type : 'SEARCH' ,  data : data, index : index}) //получения данных с фильтром
        }
    }))(TableUsers)

Проблема в том, что если я ввожу логин, он фильтрует, если кроме логина еще e-mail, то он уже фильтрует по e-mail, не учитывая логин. Т.к компонент TableUsers в функции ajax при инициализации обнуляет переменные. И я никак не могу придумать как сделать так, что бы он держал “в уме” все что я ввел.

Я думал смотреть на action редьюсера в функции ajax, но у меня не получилось это, т.к вызвать this.props в ajax не могу.

Подскажите как лучше и правильно сделать множественный фильтр с помощью redux (хотя бы теоретически)?

Тебе нужно рассуждать от стора. Придумай какой объект удобнее всего описывает условия фильтрации. Например это может быть такой объект:

// ...
filters: [{
	type: 'email',
	value: 'mail@gmail.com'
}, {
	type: 'login',
	value: 'kkk'
}]
// ...

Соответственно тебе понадобяться экшены, которые управляются с этой структурой. Экшены типа “добавить фильтр”, “убрать фильтр” итд. Ну и в самом компоненте TableUsers просто забираешь значения для фильтрации.

1 лайк

Привет, да получилось сделать так что бы система выдавала мне все данные которые ввели в фильтр и если нужно убирала их (понял принцип, до этого мне выводилось либо одно либо другое).

Но теперь не могу понять как в TableUsers оформить это, т.к видно какое либо действие только в рендере, если я там принимаю экшен и обновляю данные, они рендерятся и опять вызывают экшен и получается зацикливание.

т.е ловит экшен и рендерит у меня только компонент TableUsers, в рендере я делаю так:

render() {
        var element = [];
        const data = this.props.dataUser;
        const search = this.props.search;

        if(data !== undefined){
            if(search !== 0){
                if('login' in search || 'email' in search){
                    this.ajax(search.login, search.email);
                }
            }
            _.each(data.data.dataUser, function (i, k) {
                element[i.id] =  <tr key={k}>
                                <td>{i.id}</td>
                                <th>ID</th>
                                <th>Вкл.</th>
                                <th className = 'loginWitch'>Логин</th>
                                <th className = 'emailWitch'>E-mail</th>
                                <th>Доступ</th>
                                <th>Компания</th>
                                <th>Города</th>
                                <th>Регионы</th>
                                <th>Клиенты</th>
                                <th>Доступы</th>
                                <th>Роль</th>
                            </tr>
            }, this)
        }

т.е const data = this.props.dataUser; - это первичные данные, а const search = this.props.search; это данные с фильтром.

как тут быть? Я уже пробовал делать еще один эксеш который прерывает в рендере обновления, но мне кажется это костыль.

Запрос за данными в рендере - концептуально неверный подход. В рендере должно быть только отображение данных.

Запрос можно слать в

  • конструкторе
  • componentWillReceiveProps методе

Следующий момент. Ответ запроса надо помешать в this.state, и из this.state рендерить в render. Получится что рендер триггернет или внешнее изменение props-ов или внутреннее state-а.

1 лайк

Забей на эту мою фразу, ты уже положил данные в стор, и получаешь их из пропсов. Это более гибко чем работа через state.

1 лайк