提问人:rednate95 提问时间:11/17/2023 更新时间:11/17/2023 访问量:52
按 html 选择值 react 过滤数组
filter array by html select value react
问:
我正在尝试按选择值过滤我的数组,但我无法获得我正在寻找的结果。我希望能够单击某个选项,然后使用与该选项相关的内容重新呈现数据,但数据未显示。select
这是我尝试过滤的数组的示例,我专门针对该数组。contentType
[{
ageRange: [4, 7],
contentType: ['Animal Stories', 'Stories'],
description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
flag: "New to Yoto",
handle: "5-minute-stories-in-the-wild",
id: 1,
imgSet: {sm: {…}, md: {…}, lg: {…}, alt: null},
price: "9.99",
productType: "single-card",
runtime: 1800,
title: "5-Minute Stories: In the Wild"
},
{
ageRange: [3, 10],
contentType: ['Action & Action', 'Stories'],
description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
flag: "New to Yoto",
handle: "5-minute-stories-in-the-wild",
id: 2,
imgSet: {sm: {…}, md: {…}, lg: {…}, alt: null},
price: "3.99",
productType: "single-card",
runtime: 800,
title: "5-Minute Stories: In the Wild"
}]
这是我页面的代码:
import React, { useState, useEffect } from 'react';
import { sortBy } from '../utils/utils';
import { Products } from '../types/types';
import { fetchData } from '../endpoints/fetchData';
import '../index.css';
function App() {
const sortBy: Record<string, any> = {
duration: (prod: Products[]) => prod.sort((a, b) => a.runtime - b.runtime),
price_ascending: (prod: Products[]) =>
prod.sort((a, b) => parseInt(a.price) - parseInt(b.price)),
price_descending: (prod: Products[]) =>
prod.sort((a, b) => parseInt(b.price) - parseInt(a.price)),
zero_to_five: (prod: Products[]) =>
prod.filter((age) => age.ageRange[0] >= 0 && age.ageRange[1] <= 5),
six_to_nine: (prod: Products[]) =>
prod.filter((age) => age.ageRange[0] >= 6 && age.ageRange[1] >= 9),
};
const [products, setProducts] = useState<Products[]>([]);
const [currentPage, setCurrentPage] = useState<number>(1);
const [filterValue, setFilterValue] = useState<string>('');
const [contentTypeValue, setContentTypeValue] = useState<string>('');
const productsPerPage = 20;
const lastIndex = currentPage * productsPerPage;
const firstIndex = lastIndex - productsPerPage;
const filteredProducts = sortBy?.[filterValue]?.(products) ?? products;
const currentProducts = filteredProducts.slice(firstIndex, lastIndex);
const pages = Math.ceil(filteredProducts.length / productsPerPage);
const numbers = [...Array(pages + 1).keys()].slice(1);
useEffect(() => {
fetchData(setProducts);
}, [contentTypeValue]);
const nextPage = () => {
if (currentPage !== lastIndex) {
setCurrentPage(currentPage + 1);
}
};
const prevPage = () => {
if (currentPage !== firstIndex) {
setCurrentPage(currentPage - 1);
}
};
const movePages = (id: number) => {
setCurrentPage(id);
};
const Pagination = () => {
return (
<nav>
<ul>
<li>
<a
href="#"
className={`${currentPage === 1 ? 'none' : ''}`}
onClick={prevPage}>
Prev
</a>
</li>
{numbers.map((number) => {
return (
<li key={number}>
<a
href="#"
className={`${currentPage === number ? 'active' : ''}`}
onClick={() => movePages(number)}>
{number}
</a>
</li>
);
})}
{filteredProducts.length <= 20 ? (
<></>
) : (
<li>
<a
href="#"
className={`${currentPage === numbers.length ? 'none' : ''}`}
onClick={nextPage}>
Next
</a>
</li>
)}
</ul>
</nav>
);
};
const contentTypeList = [
...new Set(products.map((prod) => prod.contentType).flat()),
];
const handleSort = (event: React.ChangeEvent<HTMLSelectElement>) => {
setFilterValue(event?.target.value);
//goto page 1 after sort
setCurrentPage(1);
};
const handleContentTypeSort = (e: React.ChangeEvent<HTMLSelectElement>) => {
const value = e.target.value;
setContentTypeValue(value);
if (value) {
return products.filter((content: Products) =>
content.contentType.includes(contentTypeValue),
);
}
};
const mapContentTypes = () => {
return (
<>
<select
name="type"
defaultValue=""
data-testid="select"
onChange={(e) => handleContentTypeSort(e)}>
<option value="" selected defaultValue="Sort By:" disabled hidden>
Content type
</option>
{contentTypeList.map((contentType) => (
<option data-testid="type-option" value={contentType}>
{contentType}
</option>
))}
</select>
</>
);
};
const mapProducts = () => {
return (
<React.Fragment>
<div className="container">
<div className="filterContainer">
<div>
<Pagination />
</div>
<div className="filter">
<label htmlFor="type">Sort by: </label>
<select
name="type"
defaultValue=""
data-testid="select"
onChange={handleSort}>
<option
value=""
selected
defaultValue="Sort By:"
disabled
hidden>
Sort By
</option>
<option data-testid="type-option" value="price_ascending">
Price ascending
</option>
<option data-testid="type-option" value="price_descending">
Price descending
</option>
<option data-testid="type-option" value="duration">
Duration
</option>
<option data-testid="type-option" value="zero_to_five">
0-5
</option>
<option data-testid="type-option" value="six_to_nine">
6-9+
</option>
</select>
<label htmlFor="type">Content Type: </label>
{mapContentTypes()}
<button>Reset filter</button>
</div>
</div>
{currentProducts.map((product: Products) => {
return (
<div className="item" key={product.id}>
<img className="image" src={product.imgSet.sm.src} />
<div className="innerContainer">
<span>Name: {product.title}</span>
<span>Price: {product.price}</span>
<span>Stock level: {product.productType}</span>
</div>
</div>
);
})}
<Pagination />
</div>
</React.Fragment>
);
};
return (
<header className="App-header">
<div className="container">{mapProducts()}</div>
</header>
);
}
export default App;
在此函数中,我尝试过滤并触发新数据的重新渲染,但数据未显示。
const handleContentTypeSort = (e: React.ChangeEvent<HTMLSelectElement>) => {
const value = e.target.value;
setContentTypeValue(value);
if (value) {
return currentProducts.filter((content: Products) =>
content.contentType.includes(contentTypeValue),
);
}
};
我有分页和其他排序功能,但这个功能似乎没有像我希望的那样工作。我只需要能够单击,它就会根据 contentType 向相关数据显示数据。
我创建了一个 codeandsandbox 来解释我的代码正在执行以及出了什么问题: https://codesandbox.io/s/runtime-night-w65s8z?file=/src/App.js
答:
现在,您在更改处理程序中返回筛选的产品列表,该处理程序不执行任何操作。
相反,您应该在渲染时过滤产品列表。例如:
{currentProducts
.filter((content) => {
return content.contentType.includes(contentTypeValue);
})
.map((product) => {
return <div className="item" key={product.id}>...</div>;
})}
您需要像在更改处理程序中那样考虑无效值,但只需保持代码段的简单性。
在 中,您正在过滤 ,但不会使用过滤后的数组更新状态。这就是您的数据不会使用过滤后的内容重新呈现的原因。handleContentTypeSort
currentProducts
这,像这样做;
const handleContentTypeSort = (e: React.ChangeEvent<HTMLSelectElement>) => {
const value = e.target.value;
setContentTypeValue(value);
if (value) {
const filteredProducts = products.filter((content: Products) =>
content.contentType.includes(value),
);
setProducts(filteredProducts);
}
};
在这里,我们将创建一个新数组,该数组仅包含其 productssetProducts(filteredProducts)''' 的产品,因此它将触发使用过滤后的产品重新渲染组件。filteredProducts
contentType`` includes the selected value. Then, we're updating the state of
with
评论
setContentTypeValue
contentTypeValue
currentProducts