我正在为我的应用程序开发过滤器引擎。现在,我遇到了对象数据之间的迭代问题,我需要根据用户应用的过滤器数组来检查该问题。最终目标是返回与一个或多个过滤器选择匹配的对象。
这是我的代码:
const Results = () => {
const [dataStored, setDataStored] = useState([])
const filterArray = useSelector(state => state.filterArray);
const doctors = useSelector(state => state.doctors);
// let doctorsResult = doctors.map(doctor => doctor.indexOf(filterArray) !== -1 )
// let doctorsResult = doctors.map(doctor => {for(let key of Object.keys(doctor)){
// if (key === 'price' || key === 'gender' || key === 'language'){
// // setDataStored([...dataStored, doctor[key]])
// console.log("dataStored",doctor[key])}
// // return (dataStored.indexOf(filterArray) !== -1 )
// }})
let doctorsResult = doctors.map(doctor => {
Object.keys(doctor).forEach((key) => {
if (key === 'price' || key === 'gender' || key === 'language') {
setDataStored([...dataStored, doctor[key]])
console.log("dataStored", dataStored)
}
return (dataStored.indexOf(filterArray) !== -1)
})
})
每个对象都有多个属性,但是我只需要检查“价格,性别和语言”值。属性不相等,有些只是字符串,有些则是数组。到目前为止,我已经能够使用for..in和forEach循环通过属性进行迭代。我的问题是,我无法比较并返回任何数据,因为它不是数组,因此,indexOf()给我一个错误。当我尝试setDataStored([...dataStored, doctor[key]])
时,状态进入无限循环。
我对这一切还很陌生。如果有人能够以更好的方式实现这一目标,我将不胜感激。
编辑:
这是filterArray的形状 这是一个动态过滤器,开始为空然后填充
答案 0 :(得分:3)
因此,您想从两个选择器获取状态并做一些工作,然后返回结果?对于reselect
,这是完美的问题类型。重新选择是一个帮助程序,可让您记住有关状态选择器的昂贵计算。
这会给您带来什么样的感觉。
$ yarn add reselect
import React from 'react';
import { useSelector } from 'react-redux';
import { createSelector } from 'reselect';
const filterArraySelector = (state) => state.filterArray;
const doctorsSelector = (state) => state.doctors;
const filteredDoctorsSelector = createSelector(doctorsSelector, filterArraySelector, (filterArray, doctors) => {
return doctors.filter((doctor) => {
return filterArray.all((key) => {
// Do some comparison here, return true if you want to include the doctor in the results
return doctor[key] !== undefined;
});
});
});
const Results = () => {
const filteredDoctors = useSelector(filteredDoctorsSelector);
return filteredDoctors.map((doctor) => <span>{doctor}</span>);
};
您无需使用createSelector
来记住过滤,而是可以在每次渲染时简单地过滤医生。像这样:
const Results = () => {
const filterArray = useSelector((state) => state.filterArray);
const doctors = useSelector((state) => state.doctors);
const filteredDoctors = useMemo(
() =>
doctors.filter((doctor) => {
return filterArray.all((key) => {
// Do some comparison here, return true if you want to return the doctor
return doctor[key] !== undefined;
});
}),
[doctors, filterArray]
);
return filteredDoctors.map((doctor) => <span>{doctor}</span>);
};
给出一个像这样的值的filterArray:
const filterArray = ['Female', 'English'];
我们可以更新过滤器功能以针对filterArray值测试对象值。如果任何一个属性值都与filterArray值匹配,那么我们可以将医生包括在最终的filterDoctors列表中。
const Results = () => {
const filterArray = useSelector((state) => state.filterArray);
const doctors = useSelector((state) => state.doctors);
const filteredDoctors = useMemo(() => {
return doctors.filter((doctor) => {
return filterArray.some((filter) => {
return Object.values(doctor).some((value) => value === filter);
});
});
}, [doctors, filterArray]);
return filteredDoctors.map((doctor) => <span>{doctor}</span>);
};
在聊天中讨论之后:
const Results = () => {
const filterArray = useSelector((state) => state.filterArray);
const doctors = useSelector((state) => state.doctors);
const filteredDoctors = useMemo(() => {
return doctors.filter((doctor) => {
return filterArray.some((filter) => {
return Object.values(doctor).some((value) => {
// If the attribute value is an array
if (Array.isArray(value)) {
return value.some((value) => value === filter);
}
// If the attribute value is an object, get the values from the object
if (typeof value === 'object') {
return Object.values(value).some((value) => value === filter);
}
// By default, expect the value to be a string
return value === filter;
});
});
});
}, [doctors, filterArray]);
return filteredDoctors.map((doctor) => <span>{doctor}</span>);
};