【发布时间】:2021-07-07 07:04:36
【问题描述】:
我正在为一个电子商务项目开发过滤器。
它有一个活动过滤器部分,其中显示处于活动状态的过滤器,并且可以使其处于非活动状态。此功能有效,正确找到索引并删除正确的对象。我使用了一些相同的代码来创建切换过滤器活动状态的函数,但由于某种原因,即使控制台日志显示数组中的对象,并且显示对象完全相同,它也会不断返回 -1。我很困惑。
这是数组的控制台日志:
[
{
"section": "Section 1",
"option": "Option 1"
},
{
"section": "Filter Section",
"option": "Option 1"
},
{
"section": "Section 1",
"option": "Option 2"
}
]
这是我要查找的对象的控制台日志:
{
"section": "Filter Section",
"option": "Option 1"
}
然后控制台为索引记录 -1,而它显然应该是 1。
代码如下:
import styles from '../../styles/SASS/filter.module.scss';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faPlus, faMinus, faTimes, faCheck } from '@fortawesome/free-solid-svg-icons'
import { useState } from 'react';
export default function Filter(params) {
// hard coded data for dev purposes
let myFilters = {sections: [
{name: "Filter Section", options: ["Option 1", "Option 2", "Option 3"]}
]
};
let [activeFilters, setActiveFilters] = useState([{section: "Section 1", option: "Option 1"},
{section: "Filter Section", option: "Option 1"},
{section: "Section 1", option: "Option 2"}
]);
let [filters, setFilters] = useState(myFilters);
let [openSections, setOpenSections] = useState(["Active Filters"]);
let isActive = (string) => {
let section = string.split(":")[0];
let option = string.split(":")[1];
let filter = {};
filter.section = section;
filter.option = option;
let currentActiveFilters = [...activeFilters];
let index = currentActiveFilters.findIndex(activefilter => activefilter == filter);
// console.log(currentActiveFilters);
// console.log(filter)
// console.log(`Index is ${index}`)
if (index !== -1) {
return true;
} else {
return false;
}
}
let removeActiveFilter = (filter) => {
let currentActiveFilters = [...activeFilters];
let index = currentActiveFilters.findIndex((activefilter) => {
activefilter == filter;
});
currentActiveFilters.splice(index, 1);
setActiveFilters(currentActiveFilters);
}
let toggleActive = (string) => {
let section = string.split(":")[0];
let option = string.split(":")[1];
let filter = {};
filter.section = section;
filter.option = option;
let currentActiveFilters = [...activeFilters];
let index = currentActiveFilters.findIndex((activefilter) => {
// console.log(activefilter);
// console.log(filter);
// activefilter == filter;
activefilter.section == filter.section && activefilter.option == filter.option
});
if (index > 0) {
currentActiveFilters.splice(index, 1);
setActiveFilters(currentActiveFilters);
} else {
currentActiveFilters.push(filter);
setActiveFilters(currentActiveFilters);
}
}
let isOpen = (section) => {
let openedSections = [...openSections];
let index = openedSections.findIndex(openSection => openSection == section);
if (index !== -1) {
return true
} else {
return false
}
}
let toggleOpen = (section) => {
let openedSections = [...openSections];
let index = openSections.findIndex(openSection => openSection == section);
if (index === -1) {
openedSections.push(section);
setOpenSections(openedSections);
} else {
openedSections.splice(index, 1);
setOpenSections(openedSections);
}
}
return (
<div className={params.showFilter == true ? `${styles.overlay} ${styles.open}` : `${styles.overlay}`}>
<div className={styles.filter}>
<div className={styles.header}>
<p className={styles.title}>Filters</p>
</div>
<div className={styles.activeFilters}>
<div className={styles.sectionHeader} onClick={() => toggleOpen('Active Filters')}>
<p>Active Filters ({activeFilters.length})</p>
{isOpen('Active Filters') ? <FontAwesomeIcon icon={faMinus} className={styles.icon}/> : <FontAwesomeIcon icon={faPlus} className={styles.icon}/>}
</div>
<div className={activeFilters.length > 0 && isOpen('Active Filters') || isOpen('Active Filters') ? `${styles.sectionContent} ${styles.open}`: `${styles.sectionContent}`}>
{activeFilters.length < 1 ? <p className={styles.message}>You haven't applied any filters yet.</p> : <></>}
<div className={styles.filtersContainer}>
{activeFilters.map((filter) => {
return (
<div key={`${filter.section}:${filter.option}`} className={styles.activeFilter}>
<p>{filter.section}: </p>
<p>{filter.option}</p>
<FontAwesomeIcon icon={faTimes} className={styles.removeIcon} onClick={() => removeActiveFilter(filter)}/>
</div>
)
})}
</div>
</div>
</div>
{filters.sections.map((filter) => {
return (
<div key={filter.name} className={styles.filterSection}>
<div className={styles.sectionHeader} onClick={() => toggleOpen(filter.name)}>
<p>{filter.name}</p>
{isOpen(filter.name) ? <FontAwesomeIcon icon={faMinus} className={styles.icon}/> : <FontAwesomeIcon icon={faPlus} className={styles.icon}/>}
</div>
<div className={isOpen(filter.name) ? `${styles.sectionContent} ${styles.open}`: `${styles.sectionContent}`}>
{filter.options.map((option) => {
return (
<div key={`option:${filter.name}:${option}`}
className={isActive(`${filter.name}:${option}`) ? `${styles.filterChoice} ${styles.active}` : `${styles.filterChoice}`}
onClick={() => toggleActive(`${filter.name}:${option}`)}>
<div className={styles.checkbox}>
<FontAwesomeIcon icon={faCheck} className={styles.checkmark} />
</div>
<p className={styles.label}>{option}</p>
</div>
)
})}
</div>
</div>
)
})}
<div className={styles.footer}>
<button className={styles.resetBtn} onClick={() => setActiveFilters([])}>Reset Filters</button>
<button className={styles.closeBtn} onClick={() => params.setShowFilter(false)}>Close</button>
</div>
</div>
</div>
)
};
【问题讨论】:
-
您在比较对象,而不是对象属性。对象相等性由引用确定,而不是由形状/值确定,请参阅:How to determine equality for two JavaScript objects?。您需要单独比较所有相关属性以获得您期望的结果。
-
对象不是按值比较,而是我的参考(内存分配)。即使是不同变量中的相同对象也将不匹配,因为与按值评估的基元不同,对象是按引用的。此外 - 您可以轻松地在 json 对象上使用
JSON.parse(obj)而不是拆分子字符串。 -
对此的快速修复将是:
currentActiveFilters.findIndex(activefilter => JSON.stringify(activefilter) === JSON.stringify(filter))。检查这个主题 - Object comparison in JavaScript -
仅当它们的顺序相同时,最好明确地这样做
let index = currentActiveFilters.findIndex(({section, option}) => section === filter.section && option === filter.option); -
这表明您传递的引用在您删除时匹配。
标签: javascript arrays reactjs next.js