通过复选框过滤对象数组
Posted
技术标签:
【中文标题】通过复选框过滤对象数组【英文标题】:Filter array of objects through checkboxes 【发布时间】:2021-08-18 05:28:46 【问题描述】:这是React.js
过滤器问题,我被困在这里。问题是将电影的静态数据作为对象数组,我们必须根据不同复选框的选中状态过滤该数据。
静态数据:
export const data = [
id: 1,
title: 'Batman',
rating: 1,
genre: 'Action'
,
id: 2,
title: 'Superman',
rating: 5,
genre: 'Comedy'
,
id: 3,
title: 'Spiderman',
rating: 3,
genre: 'Thriller'
,
id: 4,
title: 'BananaMan',
rating: 2,
genre: 'Action'
,
id: 5,
title: 'OrangeMan',
rating: 4,
genre: 'Drama'
];
抽象的 UI 有下图,代表 2 种过滤器。
评分 类型截图:
两个过滤器都在 UI 上呈现为复选框。因此,我创建了一个名为 Checkboxes
的组件,它将采用一个名为 list
的道具,它是一个对象数组。
这个list
代表唯一的ids
复选框,这将帮助我们跟踪复选框的checked
或unchecked
状态。不同的复选框id
将保存在数组状态中。
const [checkedArray, setCheckedArray] = useState([]);
最后,我在名为App.js
的父组件内渲染了这个Checkboxes
组件两次。一个用于评分,另一个用于流派。
列表:
export const listCheckboxesRating = [
id: 0,
name: 'rating',
label: 'Any Rating'
,
id: 1,
name: 'rating1',
label: 'Rating 1'
,
id: 2,
name: 'rating2',
label: 'Rating 2'
,
id: 3,
name: 'rating3',
label: 'Rating 3'
,
id: 4,
name: 'rating4',
label: 'Rating 4'
,
id: 5,
name: 'rating5',
label: 'Rating 5'
];
export const listCheckboxesGenre = [
id: 0,
name: 'genre',
label: 'Any Genre'
,
id: 1,
name: 'action',
label: 'Action'
,
id: 2,
name: 'comedy',
label: 'Comedy'
,
id: 3,
name: 'drama',
label: 'Drama'
,
id: 4,
name: 'thriller',
label: 'Thriller'
];
复选框组件:
import useState from 'react';
import handleToggle from '../../utils';
const Checkboxes = (list, handleFilters) =>
const [checkedArray, setCheckedArray] = useState([]);
const onChangeHandler = (checkboxId) =>
const newState = handleToggle(checkboxId, checkedArray);
setCheckedArray(newState);
// Update this checked information into Parent Component
handleFilters(newState);
;
return list.map((item, index) =>
return (
<div key=index>
<input
type="checkbox"
id=item.name
checked=checkedArray.indexOf(item.id) !== -1
onChange=() => onChangeHandler(item.id)
/>
<label htmlFor=item.name>item.label</label>
</div>
);
);
;
export default Checkboxes;
我通过名为handleFilters
的函数将这些复选框的整个状态传递给父组件App.js
。可以看到这行代码。
handleFilters(newState);
App.js
组件正在保存这些复选框的状态,如下所示:
const [selected, setSelected] = useState(
rating: [],
genre: []
);
App.js 组件:
import useState from 'react';
import Checkboxes from './Checkboxes';
import data, listCheckboxesRating, listCheckboxesGenre from '../data';
const App = () =>
const [movies, setMovies] = useState(data);
const [selected, setSelected] = useState(
rating: [],
genre: []
);
/**
* This function will perform the filtration process based on the key value.
*
* @param number[] checkboxState - It will take the final state of checkboxes
* @param string key - It will help us to determine the type of filtration
*/
const handleFilters = (checkboxState, key) =>
const newFilters = ...selected;
newFilters[key] = checkboxState;
// Filtration process
for (let key in newFilters)
if (
newFilters.hasOwnProperty(key) &&
Array.isArray(newFilters[key]) &&
newFilters[key].length > 0
)
if (key === 'rating')
else if (key === 'genre')
// Save the filtered movies and update the state.
// setMovies();
setSelected(newFilters);
;
return (
<div>
movies.map((movie) => (
<div key=movie.id>
<div>Name: movie.title</div>
<div>Genre :movie.genre</div>
<div>Rating: movie.rating</div>
<hr />
</div>
))
<div className="row">
<div className="col">
<h1>Filter by Rating</h1>
<Checkboxes
list=listCheckboxesRating
handleFilters=(checkboxState) =>
handleFilters(checkboxState, 'rating')
/>
</div>
<div className="col">
<h1>Filter by Genre</h1>
<Checkboxes
list=listCheckboxesGenre
handleFilters=(checkboxState) =>
handleFilters(checkboxState, 'genre')
/>
</div>
</div>
</div>
);
;
export default App;
两个过滤器的复选框checked
或unchecked
状态工作正常,并且在父selected
状态中使用ids
正确更新,类似这样。
const [selected, setSelected] = useState(
rating: [1,2,3],
genre: [2,4]
);
但这是我被卡住的令人困惑的部分。如何映射这些复选框ids
并根据这些ids
过滤数据?
我在App.js
组件handleFilters(checkboxState, key)
中定义了一个函数,我想在其中迭代selected
状态以执行过滤过程,但我的脑子没有逻辑,我需要帮助。
工作演示:
repository link.
【问题讨论】:
【参考方案1】:因此,我必须对您的代码进行一些更改才能解决正确的过滤问题:
-
在
listCheckboxesRating
和listCheckboxesGenre
上都添加了value
键,用于过滤。
export const listCheckboxesGenre = [
id: 0,
name: 'genre',
label: 'Any Genre',
value: ''
,
...
-
更新了
onChangeHandler
以将value
传递回handleFilters
而不是id
const onChangeHandler = (checkboxId) =>
// ...
handleFilters(newState.map((id) => list[id].value));
;
-
创建了几个过滤器函数来过滤电影。
const handleFilters = (checkboxState, key) =>
const newFilters = ...selected ;
newFilters[key] = checkboxState;
const hasFilters =
newFilters.rating.length > 0 || newFilters.genre.length > 0;
const filterRating = (module) =>
newFilters.rating.includes(0) ||
newFilters.rating.includes(module.rating);
const filterGenre = (module) =>
newFilters.genre.includes('') || newFilters.genre.includes(module.genre);
const filteredMovies = data.filter(
(m) => !hasFilters || filterRating(m) || filterGenre(m)
);
setMovies(filteredMovies);
setSelected(newFilters);
;
工作演示:
【讨论】:
我检查了这段代码,但Genre
过滤不起作用。
我认为你是对的,我忘了第一个过滤器没有考虑流派,让我来解决这个问题。
@VenNilson 我用工作演示创建了您的代码和框的副本。
向这个列表添加值很棒。当我选择 Rating 2
和流派 action
时还有一件事,结果应该只显示 1 部电影,而不是在结果中显示 2 部电影。我很好奇这是什么原因?
哦,那基本上是因为我要使用OR logic
,您可以尝试使用我在代码中留下注释的AND logic
。【参考方案2】:
我做了一些重构。
-
使数据更加通用。
export const listCheckboxesRating =
key: 'rating',
data: [
id: 1,
name: 'rating1',
label: 'Rating 1',
value: 1
,
...
-
重构 Checkbox 组件并仅传递数据。
<Checkboxes
list=listCheckboxesGenre
handleFilters=handleFilters
/>
-
使过滤过程具有价值和关键。
// Filtration process
let filteredMovies = data.filter((movie) =>
for (let key in newFilters)
if (
newFilters.hasOwnProperty(key) &&
Array.isArray(newFilters[key]) &&
newFilters[key].length > 0
)
if (
newFilters[key].findIndex((value) => movie[key] === value) === -1
)
return false;
return true;
);
工作演示: https://codesandbox.io/s/react-filter-forked-gs2b2?file=/src/components/App.js
【讨论】:
以上是关于通过复选框过滤对象数组的主要内容,如果未能解决你的问题,请参考以下文章