javascript - 过滤后保留数据对象

标签 javascript reactjs redux material-ui

小背景介绍

我目前在我的项目的用户管理页面上工作,在这里遇到了一个小问题。我有一个包含一些 material-ui`s Usercard 的表。对于使用我的系统的每个用户,都存在一张卡。这些卡片是根据我的数据库中的数据生成的,然后写入 redux store

管理员可以与更改某些用户数据的数据库进行多次交互。提供一种简单的方法来查找特定用户 <TextField />实现过滤器是用户卡表。

这里提到的所有东西都有效!

问题

如简介中所述,数据存储在 redux store 中。当我过滤数据时,会调度一个 Action

    export const FILTER_ALL_USER_BY_NAME = "FILTER_ALL_USER_BY_NAME"
    export const FILTER_ALL_USER_BY_DEPARTMENT = "FILTER_ALL_USER_BY_DEPARTMENT"

    export default function filterAllUser(filter, filterOption){
        return (dispatch, getState) => {
            if(filterOption === 'name'){
                return dispatch (filterUserByName(filter))
            }else{
                return dispatch (filteUserByDepartment(filter))
            }
        }
    }

    function filterUserByName(filter){
        return {
            type: FILTER_ALL_USER_BY_NAME,
            filter: filter
        }
    }

    function filteUserByDepartment(filter){
        return {
            type: FILTER_ALL_USER_BY_DEPARTMENT,
            filter: filter
        }
    }

Reducer

即使 reducer 有效,这也是我的问题的主要原因

为什么?

这是因为,当我过滤数据时,我无法真正地过滤状态,而是返回一个新的状态对象,这导致我遇到问题 allUserDatafilteredUserData更改用户数据后不同步

让我用代码解释一下

    function allUser(state = {allUserData: []}, action){
        switch (action.type){
            case 'REQUEST_ALL_USER':
                return Object.assign({}, state, {
                    isFetching: true
                });
            case 'RECEIVE_ALL_USER':
                return Object.assign({}, state, {
                    isFetching: false,
                    allUserData: action.items
                });
            case 'FILTER_ALL_USER_BY_NAME':
                return Object.assign({}, state, {
                    filteredUserData: state.allUserData.filter(user => user.userNameLast.toLowerCase().indexOf(action.filter.toLowerCase()) >= 0)
                });
            case 'FILTER_ALL_USER_BY_DEPARTMENT':
                return Object.assign({}, state, {
                    filteredUserData: state.allUserData.filter(user => user.departmentName.toLowerCase().indexOf(action.filter.toLowerCase()) >= 0)
                });
            default:
                return state
        }
    }

但是当我尝试过滤原始状态并且用户删除过滤器时,与过滤器不匹配的数据就消失了。

    case 'FILTER_ALL_USERS': return allUsers.filter(user => user.userNameLast.toLowerCase().indexOf(action.filter.toLowerCase()) >= 0);

如何过滤状态,但保留数据

最佳答案

根据要求,我为您整理了一些代码。它会像下面这样。

作为旁注,我会将过滤器传递为 { field: 'userLastName', text: your filter text} 作为过滤条件。或者为了使其更具可扩展性,您可以传递过滤器处理程序而不是上面的文本。这样您就可以拥有任何类型的过滤器,而不仅仅是文本过滤器。

export default function allUser(state = {allUserData: [], filters: {}, filteredUserData: []}, action){
  switch (action.type){
    case 'REQUEST_ALL_USER':
      return {
        ...state,
        isFetching: true
      };
    case 'RECEIVE_ALL_USER':
      return {
        ...state,
        isFetching: false,
        allUserData: action.items,
        filteredUserData: filterData(action.items, state.filters),
      };
    case 'FILTER_ALL_USER_BY_NAME':
    {
      const updatedFilters = {
        ...state.filters,
        userNameLast: action.filter
      }
      return {
        ...state,
        filteredUserData: filterData(state.allUserData, updatedFilters),
        filters: updatedFilters
      };
    }
    case 'FILTER_ALL_USER_BY_DEPARTMENT':
    {
      const updatedFilters = {
        ...state.filters,
        departmentName: action.filter
      }
      return {
        ...state,
        filteredUserData: filterData(state.allUserData, updatedFilters),
        filters: updatedFilters
      };
    }
    default:
      return state
  }
}

const filterData = (users, filters) => {
  return users.filter(filterFn(filters));
};

const filterFn = filters => item => Object.keys(filters).reduce((res, filter) => {
  return res && item[filter].toLowerCase().indexOf(filters[filter].toLowerCase()) >= 0;
}, true);

单元测试

import usersReducer from './users';

describe('usersReducer', () => {
  describe('RECEIVE_ALL_USER', () => {
    const RECEIVE_ALL_USER = 'RECEIVE_ALL_USER';
    it('should replace users in state', () => {
      const initialState = { isFetching: false, allUserData: [{ name: 'A' }], filters: {}};
      const newUsers = [{ name: 'B' }];
      const newState = { ...initialState, allUserData: newUsers, filteredUserData: newUsers};
      expect(usersReducer(initialState, { type: RECEIVE_ALL_USER, items: newUsers })).toEqual(newState);
    })
  })
  describe('FILTER_ALL_USER_BY_NAME', () => {
    let FILTER_ALL_USER_BY_NAME = 'FILTER_ALL_USER_BY_NAME';
    it('should filter users by name', () => {
      const initialState = { isFetching: false, allUserData: [{ userNameLast: 'Doe' }, { userNameLast: 'Smith' }], filters: {}};
      const filterText = 'd';
      const finalState = { isFetching: false,
        allUserData: [{ userNameLast: 'Doe' }, { userNameLast: 'Smith' }],
        filters: { userNameLast: filterText },
        filteredUserData: [{ userNameLast: 'Doe' }]
      };

      expect(usersReducer(initialState, { type: FILTER_ALL_USER_BY_NAME, filter: filterText})).toEqual(finalState);
    })
  })
  describe('FILTER_ALL_USER_BY_DEPARTMENT', () => {
    let FILTER_ALL_USER_BY_DEPARTMENT = 'FILTER_ALL_USER_BY_DEPARTMENT';
    it('should filter users by department', () => {
      const initialState = { isFetching: false, allUserData: [{ departmentName: 'IT' }, { departmentName: 'Human Resources' }], filters: {}};
      const filterText = 'it';
      const finalState = {
        ...initialState,
        filters: { departmentName: filterText },
        filteredUserData: [{ departmentName: 'IT' }]
      };

      expect(usersReducer(initialState, { type: FILTER_ALL_USER_BY_DEPARTMENT, filter: filterText})).toEqual(finalState);
    })
  })
});

关于javascript - 过滤后保留数据对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39370962/

相关文章:

javascript - 如何在 webpack 中应用 createProxyMiddleware?

reactjs - react 路由器,history.push 之后的代码运行?

reactjs - React Router v6 useNavigate 与 MUI Drawer

javascript - 在 redux 操作中查询 api 时出现无限循环

javascript - 打电话哪个更贵?显示-隐藏 dom 节点或创建-删除 dom 节点

javascript - 单击删除 append

reactjs - React.createElement : type is invalid -- expected a string, 但得到:对象

javascript - 如何让forceUpdate()重新渲染我的WIzard表单?

JavaScript 堆内存不足 (Nodejs)

javascript - iPad 需要三点触控来处理 JavaScript 点击事件