Javascript 过滤后保留数据对象
小背景介绍 我目前正在处理项目的用户管理页面,遇到了一个小问题。我有一个表,其中包含一些材料用户界面的用户卡。使用我的系统的每个用户都有一张卡。该卡由来自我的数据库的数据生成,然后写入redux存储 管理员可以与数据库进行多次交互,以更改某些用户数据。为了提供一种查找特定用户的简便方法,实现了一种过滤用户卡表的Javascript 过滤后保留数据对象,javascript,reactjs,redux,material-ui,Javascript,Reactjs,Redux,Material Ui,小背景介绍 我目前正在处理项目的用户管理页面,遇到了一个小问题。我有一个表,其中包含一些材料用户界面的用户卡。使用我的系统的每个用户都有一张卡。该卡由来自我的数据库的数据生成,然后写入redux存储 管理员可以与数据库进行多次交互,以更改某些用户数据。为了提供一种查找特定用户的简便方法,实现了一种过滤用户卡表的 这里提到的所有东西都有效 问题 如介绍中所述,数据存储在redux存储中。当我过滤数据时,一个动作被调度 export const FILTER_ALL_USER_BY_NAME
这里提到的所有东西都有效
问题
如介绍中所述,数据存储在redux存储中。当我过滤数据时,一个动作被调度
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
}
}
减速器
即使减速器工作正常,这也是我出现问题的主要原因
为什么?
这是因为,当我过滤数据时,我无法真正过滤状态,而不是返回一个新的状态对象,这会导致问题,allUserData
和filteredUserData
在用户数据更改后失去同步
让我用代码解释一下
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);
})
})
});
为什么不将筛选器和filteredUsers存储在状态中,并且在任何时候更新筛选器或数据时,也更新filteredUsers?这可能会起作用,但对我来说,这似乎是解决此问题的一个不干净的解决方案。唯一的另一个选择是将筛选器存储在状态中,每次需要筛选用户时,您可以手动或使用类似“重新选择”的方式对其进行动态筛选。您是否可以用代码表达您的第一条评论?下面添加了代码作为答案。很棒的工作伙伴。非常感谢你的帮助!我刚刚用这个换了我的旧减速机,没有任何改动,它就可以工作了!如果感兴趣,我也可以粘贴我为这些编写的测试。它们是基本测试,不包括边缘情况,但它们有效!!是的,我很想看到他们!增加了单元测试。但正如我所说的,它们只是基本测试,并不涵盖所有情况,所以如果您想使用它们,您需要编写更多的测试。