我在行中有4个下拉式多选过滤器。
需要渲染并在每个选中的选项上。 我需要在新数组中添加选定的选项,并更新当前数组-> object.property.selected = false / true。
我正在搜索对象的槽形数组,每个对象的一个属性都有对象的数组。
您可以在此代码笔上找到代码示例:https://codepen.io/nikolatrajkovicits/pen/JqpWOX?editors=0012
以下是该数组的外观:
export const getFiltersList = () => [
{
title: 'Taxonomy',
options: [
{
id: 0,
name: 'Competitions',
selected: false,
key: 'Taxonomy'
},
{
id: 1,
name: 'Events',
selected: false,
key: 'Taxonomy'
},
{
id: 2,
name: 'Data',
selected: false,
key: 'Taxonomy'
},
{
id: 3,
name: 'Organisations',
selected: false,
key: 'Taxonomy'
},
{
id: 4,
name: 'Players',
selected: false,
key: 'Taxonomy'
},
{
id: 5,
name: 'Teams',
selected: false,
key: 'Taxonomy'
}
]
},
{
title: 'Source',
options: [
{
id: 0,
name: 'Facebook',
selected: false,
key: 'Source'
},
{
id: 1,
name: 'Twitter',
selected: false,
key: 'Source'
},
{
id: 2,
name: 'Instagram',
selected: false,
key: 'Source'
},
{
id: 3,
name: 'Websites',
selected: false,
key: 'Source'
}
]
},
{
title: 'Timeframe',
options: [
{
id: 0,
name: 'Past hour',
selected: false,
key: 'Timeframe'
},
{
id: 1,
name: 'Past 24 hours',
selected: false,
key: 'Timeframe'
},
{
id: 2,
name: 'Past week',
selected: false,
key: 'Timeframe'
},
{
id: 3,
name: 'Past month',
selected: false,
key: 'Timeframe'
},
{
id: 4,
name: 'Past year',
selected: false,
key: 'Timeframe'
}
]
},
{
title: 'Location',
options: [
{
id: 0,
name: 'Location 1',
selected: false,
key: 'Location'
},
{
id: 1,
name: 'Location 2',
selected: false,
key: 'Location'
},
{
id: 2,
name: 'Location 3',
selected: false,
key: 'Location'
},
{
id: 3,
name: 'Location 4',
selected: false,
key: 'Location'
}
]
}
];
这是算法:
selectFilter = ({ id, key }) => {
const { filtersList, selectedFilters } = this.state;
const tempFilters = filtersList;
const tempSelected = selectedFilters;
const i = tempSelected.length;
tempFilters.forEach((filter) => {
if (filter.title === key) {
filter.options.forEach((option) => {
if (option.id === id) {
option.selected = !option.selected;
const isFilterExist = tempSelected.filter(
(selectedFilter) => selectedFilter.name === option.name
);
if (!isFilterExist.length) {
const selectedItem = { name: option.name, key, id };
tempSelected[i] = selectedItem;
}
}
});
}
});
this.setState({
filtersList: tempFilters,
selectedFilters: tempSelected
});
};
在代码笔上,您可以找到纯JavaScript代码的版本。
如何使搜索引擎算法更快更清洁?
有任何建议文章,教程,评论吗?
答案 0 :(得分:1)
如果我是你,我将在使用Json对象之前更改其结构。例如:如果Json成为键,则为值对,其中键为标题,值为代表选项的数组。这将使您摆脱第一个循环,并像散列表的复杂性一样获得o(1)中的选项列表。 注意:我假设这里的标题是唯一的。 我要进行的第二个更改:您想按ID进行搜索,并且从您提到的示例中,选项数组按ID进行排序,这意味着第一个元素的ID为= 0,并且它的索引为0等。因此,如果新表示形式的值是数组索引i的元素访问也为o(1),这样您也将摆脱第二个循环。 注意:如果标题不是唯一的,或者选项ID没有排序,则需要更新示例以获取更好的解决方案。
答案 1 :(得分:1)
因此,正如您标记的那样,我有一个React实现。
简而言之,我考虑了两个问题(data
和state
),并将它们从入站数据中分离出来。另外,您输入的数据具有2个不必要的属性(selected
和key
)。
key
-这是您在return函数期间添加的react实现。我使用了您的标题,因为它在每个对象中都是唯一的。
selected
-数据应包含进入应用程序的重要属性,它比数据更能被归类为应用程序状态。如果采用这种方法,则会增加更多的计算开销。选择一个项目时,您必须将所有其他实例更新为false
。我将此状态提升到了主应用程序。
这是我写的代码:
dropdown-data.json
:
[
{
"title": "Taxonomy",
"options": [
{
"id": 0,
"name": "Competitions"
},
{
"id": 1,
"name": "Events"
},
{
"id": 2,
"name": "Data"
},
{
"id": 3,
"name": "Organisations"
},
{
"id": 4,
"name": "Players"
},
{
"id": 5,
"name": "Teams"
}
]
},
{
"title": "Source",
"options": [
{
"id": 0,
"name": "Facebook"
},
{
"id": 1,
"name": "Twitter"
},
{
"id": 2,
"name": "Instagram"
},
{
"id": 3,
"name": "Websites"
}
]
},
{
"title": "Timeframe",
"options": [
{
"id": 0,
"name": "Past hour"
},
{
"id": 1,
"name": "Past 24 hours"
},
{
"id": 2,
"name": "Past week"
},
{
"id": 3,
"name": "Past month"
},
{
"id": 4,
"name": "Past year"
}
]
},
{
"title": "Location",
"options": [
{
"id": 0,
"name": "Location 1"
},
{
"id": 1,
"name": "Location 2"
},
{
"id": 2,
"name": "Location 3"
},
{
"id": 3,
"name": "Location 4"
}
]
}
]
<App />
:
import React from "react";
import dropdownData from "./dropdown-data.json";
const Dropdown = ({ options = [], ...props }) => (
<select {...props}>
{options.map(({ id, ...option }) => (
<option key={id}>{option.name}</option>
))}
</select>
);
const App = () => {
const [data, setData] = React.useState({});
return (
<>
{/* A debugging helper :) */}
<pre>{JSON.stringify(data, null, 2)}</pre>
{dropdownData.map(({ title, options }) => (
<Dropdown
key={title}
{...{ options }}
onChange={({ target }) =>
setData({
...data,
[title.toLowerCase()]: target.value
})
}
/>
))}
</>
);
};
export default App;
pre
标签在下面显示了要返回的数据。由于初始状态有一个空对象,因此您的state
不会填充未经修改/不需要的数据。
让我知道这有什么帮助,这是create-react-app
中的2个文件。
答案 2 :(得分:1)
首先这两个都是不必要的:
const tempFilters = filtersList;
const tempSelected = selectedFilters;
变量are references to the exact same objects,您已经有了这些变量。您可以简单地分别使用filtersList
和selectedFilters
来代替tempFilters
和tempSelected
。
tempFilters.forEach((filter) => {
if (filter.title === key) {`
由于.forEach
的整体是if
,因此这表明您需要使用.filter
来代替。
tempFilters.filter((filter) => filter.title === key)`
也一样,当您进入if
filter.options.forEach((option) => {
if (option.id === id) {
您可以简化为
filter.options.filter((option) => option.id === id)
继续,这条线很浪费
const isFilterExist = tempSelected.filter(
(selectedFilter) => selectedFilter.name === option.name
);
当您感兴趣的只是是否有任何与谓词匹配的项时,无需在整个数组上运行.filter
。使用.some
代替,它直接为您提供布尔值:
const isFilterExist = tempSelected.some(
(selectedFilter) => selectedFilter.name === option.name
);
此外,由于您总是在反转布尔值,因此找到相反的对象会更简单-如果不存在过滤器 -反转谓词并使用.every
即可那。推理是元素的 some 匹配,但是您想要相反的选择,这在逻辑上是元素的 every 与谓词的完全相反。最后,我将名称更改为使用has
听起来更自然。
const hasNoFilter = tempSelected.every(
(selectedFilter) => selectedFilter.name !== option.name
);
因此,首先,可以将代码重写为以下内容:
selectFilter = ({ id, key }) => {
const { filtersList, selectedFilters } = this.state;
const i = selectedFilters.length;
filtersList
.filter((filter) => filter.title === key)
.forEach(filter => {
filter.options
.filter((option) => option.id === id)
.forEach(option => {
option.selected = !option.selected;
const hasNoFilter = tempSelected.every(
(selectedFilter) => selectedFilter.name !== option.name
);
if (hasNoFilter) {
const selectedItem = { name: option.name, key, id };
selectedFilters[i] = selectedItem;
}
});
});
this.setState({
filtersList,
selectedFilters
});
};
这使得对代码进行推理变得容易一些。
似乎您的过滤器具有唯一的标题,而其中的选项具有唯一的ID,这意味着title + ID的组合也将是唯一的。
请记住,您对单个值感兴趣,而不是对任何数量的感兴趣,因此您无需执行所有循环。您可以使用.find
来获取您感兴趣的值,从而使整个代码更易于阅读:
selectFilter = ({ id, key }) => {
const { filtersList, selectedFilters } = this.state;
const filter = filtersList.find((filter) => filter.title === key);
const option = filter.options.find((option) => option.id === id)
option.selected = !option.selected;
const hasNoFilter = tempSelected.every(
(selectedFilter) => selectedFilter.name !== option.name
);
if (hasNoFilter) {
const selectedItem = { name: option.name, key, id };
selectedFilters.push(selectedItem);
}
this.setState({
filtersList,
selectedFilters
});
};
}
由于此代码仅适用于单个项目,因此您不需要该行
const i = selectedFilters.length;
,因为您将在数组中进行单个插入。以前,所有循环中的行selectedFilters[i] = selectedItem;
建议您将多个值插入,但所有值都应放在同一位置,以便仅保留最后一个。一个简单的.push
就足以附加到末尾。