首页 > 解决方案 > 如何实现 React Redux 搜索和复选框过滤器

问题描述

我正在尝试在我的反应项目中实现搜索/过滤器,但似乎无法正确处理。 截屏

这是用户应该能够做到的:

  1. 按文本过滤
  2. 使用复选框按位置过滤
  3. 或按工作类别过滤

我现在拥有的是我可以按文本和复选框进行过滤,但我希望用户能够按文本搜索,例如“达拉斯”、“信息技术”、“销售”,然后按类别进一步过滤或使用从文本搜索返回的数据按位置。

这是我的设置:

  1. 按文本搜索使用 reducer 按搜索文本过滤数组
  2. 检查位置或类别复选框将值存储在类别或关键字数组中
  3. 在组合减速器文件中,我过滤存储中的作业数组并使用重新选择记住它。

我的搜索文本和复选框功能有一些小故障。按位置过滤复选框功能本身可以正常工作;however, when a checkbox is selected, and I enter search text, checkbox gets deselected. 当在输入字段中输入文本时,我希望复选框仍然被选中并显示在窗口中。

我是新手,任何帮助、建议或对此功能的更好方法将不胜感激。

搜索表格.JS:

import React, {Component} from 'react';
//import {FormGroup, FormControl, InputGroup} from 'react-bootstrap';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { searchJobs, getJobs } from '../actions/jobaction';
import {selectKeywordCity,deselectKeywordCity} from '../actions/selectDeselectCityAction';
import {selectKeywordCategory,deselectKeywordCategory} from '../actions/selectDeselectCategoryAction';

class Search extends Component{
    constructor(props){
        super();
        this.state = {
            keyword:'',
            checked:[]
        };
        this.handleChk = this.handleChk.bind(this);
    }

    handleInput = (event) => {
        this.setState({
            keyword: event.target.value
        });
        this.props.searchJobs(this.state.keyword);
    }

/*  handleSearch = (event) => {
        event.preventDefault();
        this.props.getJobs(this.state.keyword);
    } */

    clearForm = () => {
        this.inputSearch.value = "";
        this.setState({
            keyword: this.inputSearch.value
        });
        this.props.getJobs();
    }

    handleChk = (e, keyword, type) => {
        if(type==='city'){
            e.target.checked ? this.props.selectKeywordCity(keyword) : this.props.deselectKeywordCity(keyword);
        }else if(type==='category'){
            e.target.checked ? this.props.selectKeywordCategory(keyword) : this.props.deselectKeywordCategory(keyword);
        }

    }

    //Render Cities
    renderCities(data){
        if(data){
            const cities = Object.keys(data).map(el => {
                    return data[el].city
                }).sort()
                .reduce((city,name) => {
                    const cityCount = city[name] ? city[name] + 1 : 1;

                    return{
                        ...city, [name]:cityCount,
                    };

                },{});
            return Object.keys(cities).map((keyname, index) => {
                    return (
                        <li key={keyname}>
                            <input type="checkbox" 
                            onChange={e=>this.handleChk(e,keyname,'city')}
                            className="chkbox"
                        />
                                {keyname}
                            <span className="pull-right">{cities[keyname]}</span> 
                        </li>)
                    })
        }else{
                return("nada")
        }
    }

    //Render Job Categories

    renderCategories(data){
        if(data){
            const categories = Object.keys(data).map(el => {
                    return data[el].category
                }).sort()
                .reduce((category,name) => {
                    const categoryCount = category[name] ? category[name] + 1 : 1;

                    return{
                        ...category, [name]:categoryCount,
                    };

                },{});
            return Object.keys(categories).map((keyname, index) => {
                    return (
                        <li key={keyname}>
                            <input type="checkbox" 
                            onChange={e=>this.handleChk(e,keyname,'category')}
                            className="chkbox"
                        />
                                {keyname}
                            <span className="pull-right">{categories[keyname]}</span> 
                        </li>)
                    })
        }else{
                return("nada")
        }
    }

    render(){

        let closeBtn = null;

        if(this.state.keyword){
            closeBtn = (<i className="fa fa-times" onClick={this.clearForm}></i>);
        }

        return(
            <div>
                <div className="side-search">
                    <i className="fa fa-search"></i>
                    <input type="text" 
                            placeholder="Keyword Search" 
                            ref={el => this.inputSearch = el}
                            onChange={this.handleInput}
                            value={this.state.keyword}
                    />

                    {closeBtn}
                </div>
                <div className="chk_boxes">
                    <h4>Location</h4>
                    <ul>
                        {
                            this.renderCities(this.props.jobs)
                        }
                    </ul>
                </div>
                <div className="chk_boxes">
                    <h4>Category</h4>
                    <ul>
                        {
                            this.renderCategories(this.props.jobs)
                        }
                    </ul>
                </div>
            </div>
            )
    }
}

function mapStateToProps(state){
    return{
        jobs: state.jobs.jobs
    }
}

function mapDispatchToProps(dispatch){
    return bindActionCreators({searchJobs, 
                               getJobs,
                               selectKeywordCity,
                               deselectKeywordCity,
                               selectKeywordCategory,
                               deselectKeywordCategory},
                               dispatch)
}
export default connect(mapStateToProps,mapDispatchToProps)(Search);

工作:

import axios from 'axios';
const FETCH_URL = 'http://localhost:3006';

/* GET ALL JOB LISTINGS */
export function getJobs(){
    return function(dispatch){
        axios.get(`${FETCH_URL}/jobs`)
        .then(function(response){
            dispatch({type:'GET_JOBS',payload:response.data})
        }).catch(function(err){
            dispatch({type:'GET_JOBS_ERROR', payload:err});
        })
    }
}

/* GET ALL JOB LISTINGS */
export function searchJobs(keyword){
    return function(dispatch){
        axios.get(`${FETCH_URL}/jobs?q=${keyword}`)
        .then(function(response){
            dispatch({type:'SEARCH_JOBS',payload:response.data})
        }).catch(function(err){
            dispatch({type:'SEARCH_JOBS_ERROR', payload:err});
        })
    }
}

工作清单减少器:

export function Listings (state={}, action){
    switch(action.type){
        case 'GET_JOBS':
        return{...state, jobs:action.payload}
        case 'SEARCH_JOBS':
        return{...state, jobs:action.payload}
        default:
        return state;
    }
}

SELECTDESELECT(复选框)减速器:

const INITIAL_STATE = {
    keywords:[]
}
export function filterCity(state=INITIAL_STATE, action){
    switch(action.type){
        case 'SELECT_CITY':
        return{
            keywords:[...state.keywords, action.payload]
        }
        case 'DESELECT_CITY':
        const currentKeywordToDelete = [...state.keywords];
        const indexOfKeyword = currentKeywordToDelete.findIndex(function(keyword){
            return keyword === action.payload
        });
        return{
            keywords:[...state.keywords.slice(0,indexOfKeyword), ...currentKeywordToDelete.slice(indexOfKeyword+1) ]
        }
        default:
            return state;
    }
}

组合减速机:

    import {combineReducers} from 'redux';
import {createSelector} from 'reselect'; 
import {Listings} from './listingsReducer';
import {filterCity} from './select-deselect-city';
import {filterCategory} from './select-deselect-category';

const reducer = combineReducers({
    jobs: Listings,
    keywords: filterCity,
    category: filterCategory
});

export const selectJobList = (state) => state.jobs.jobs;
export const selectCities = (state) => state.keywords.keywords;
//export const selectCategories = (state) => state.categories.categories;

export  const selectFilteredJobs = createSelector(
    selectJobList,selectCities,
    (jobs,cities) => {

        if(cities && cities.length > 0){
            const filteredData = Object.keys(jobs)
                .filter(key => cities.includes(jobs[key].city))
                .reduce((obj, key) => {
                    return [...obj, {...jobs[key]}]
                  }, []);
                //console.log(filteredData);
            return filteredData;
        }else{
            return jobs
        }
    } 
)

export default reducer;

JSON数据:

{
    "jobs": [
        {
          "id": 1,
          "title": "Financial Analyst II",
          "description": "At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. .",
          "category": "Sales",
          "dept": "Finance",
          "date": "07/11/2018",
          "experience": ["Bachelors Degree","Five years of sales experience"],
          "city": "Dallas",
          "state":"Texas",
          "salary": "10,000"
       },
       {
          "id": 2,
          "title": "Application Support Speacialist",
          "description": "At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat.",
          "category": "Information Technology",
          "dept": "Accounting",
          "date": "07/10/2018",
          "experience": ["Bachelors Degree","Two years of sales experience"],
          "city": "Dallas",
          "state":"Texas",
          "salary": "20,000"
       }
}

标签: react-redux

解决方案


推荐阅读