我正在尝试按价格从低到高或从高到低对产品进行排序,这是我以前在 vanilla JS 中做过的事情,但这次是在 React 中。我有一个下拉列表来选择所需的顺序和实际功能
我尝试按价格从低到高或从高到低对产品进行排序,这是我以前在 vanilla JS 中做过的事情,但这次是在 React 中。我有一个下拉菜单来选择所需的顺序,实际功能可以工作,但不是我需要的方式。
在我的本地版本代码中,如果您从下拉列表中选择排序顺序,它此时不会执行任何操作,但是如果您随后按品牌或类别筛选产品,它会同时应用品牌(或类别)过滤器和所选价格排序顺序过滤器。然后,您可以从此时将排序顺序从低到高更改为高到低或反之亦然。
因此,它似乎确实正确应用了所选的排序顺序,但它只是没有在下拉菜单中选择时呈现 useState 更改,我不确定为什么。
简而言之,以下是控制排序顺序功能的位:
const [filterData, setFilterData] = useState(productDataList.products || []);
const sortItems = (e) => {
console.log('Sort');
const sortedProducts = filterData.sort((a, b) => {
if (e.value == "LowToHigh") {
console.log('sorted low to high');
if (a.price < b.price) {
return -1;
} else {
return 1;
}
} else if (e.value == "HighToLow") {
console.log('sorted high to low');
if (a.price > b.price) {
return -1;
} else {
return 1;
}
}
});
setFilterData(sortedProducts);
};
return (
<select id="sortDropDown" onChange={(e) => sortItems(e.target)}>
<option value="default">Sort by:</option>
<option value="LowToHigh">Low to high</option>
<option value="HighToLow">High to low</option>
</select>
)
希望这足以让某人帮助提供修复信息,因为我很困惑为什么从下拉列表中选择一个选项时它没有更新。
如果没有,我已经在下面为页面添加了更多代码(虽然它是一个稍微精简的版本,通常分为几个组件,我试图在下面合并它,但如果需要任何其他东西来提供帮助,请告诉我。
提前致谢。
const {useState, useEffect} = React
const productDataList = {
"products": [
{
"id": 1,
"title": "Essence Mascara Lash Princess",
"category": "beauty",
"price": 9.99,
"brand": "Essence",
"thumbnail": "https://cdn.dummyjson.com/products/images/beauty/Essence%20Mascara%20Lash%20Princess/thumbnail.png"
},
{
"id": 2,
"title": "Eyeshadow Palette with Mirror",
"category": "beauty",
"price": 19.99,
"brand": "Glamour Beauty",
"thumbnail": "https://cdn.dummyjson.com/products/images/beauty/Eyeshadow%20Palette%20with%20Mirror/thumbnail.png"
},
{
"id": 3,
"title": "Powder Canister",
"category": "beauty",
"price": 14.99,
"brand": "Velvet Touch",
"thumbnail": "https://cdn.dummyjson.com/products/images/beauty/Powder%20Canister/thumbnail.png"
},
{
"id": 4,
"title": "Dior J'adore",
"category": "fragrances",
"price": 89.99,
"brand": "Dior",
"thumbnail": "https://cdn.dummyjson.com/products/images/fragrances/Dior%20J'adore/thumbnail.png"
},
{
"id": 5,
"title": "Dolce Shine Eau de",
"category": "fragrances",
"price": 69.99,
"brand": "Dolce & Gabbana",
"thumbnail": "https://cdn.dummyjson.com/products/images/fragrances/Dolce%20Shine%20Eau%20de/thumbnail.png"
},
{
"id": 6,
"title": "Annibale Colombo Sofa",
"category": "furniture",
"price": 2499.99,
"brand": "Annibale Colombo",
"thumbnail": "https://cdn.dummyjson.com/products/images/furniture/Annibale%20Colombo%20Sofa/thumbnail.png"
},
],
"total": 194,
"skip": 0,
"limit": 36
}
const App = () => {
const [productsLimit, setProductsLimit] = useState(productDataList.limit)
const [filterData, setFilterData] = useState(productDataList.products || []);
const [categories, setCategories] = useState([]);
const [brands, setBrands] = useState([]);
useEffect(() => {
let filteredCategories = [],
filteredBrands = [];
productDataList.products.forEach((product) => {
if (!filteredCategories.includes(product.category)) {
filteredCategories.push(product.category);
}
if (!filteredCategories.includes(product.brand)) {
filteredBrands.indexOf(product.brand) == -1 && product.brand != '' && product.brand != undefined && product.brand != null ? filteredBrands.push(product.brand) : null;
}
});
setCategories(filteredCategories);
setBrands(filteredBrands);
}, []);
const productFilters = (products, filt) => {
let filteredProducts = [];
if (categories.includes(filt)) {
filteredProducts = products.category.toLowerCase() === filt.toLowerCase();
} else if (brands.includes(filt)) {
filteredProducts = products.brand === filt;
}
return filteredProducts;
};
const filter = (byFilter) => {
if (byFilter) {
let productsData = [...productDataList.products];
productsData = productsData.filter((filter) => {
return productFilters(filter, byFilter);
});
setFilterData(productsData);
} else {
setFilterData(productDataList.products);
}
};
const sortItems = (e) => {
console.log('Sort');
const sortedProducts = filterData.sort((a, b) => {
if (e.value == "LowToHigh") {
console.log('sorted low to high');
if (a.price < b.price) {
return -1;
} else {
return 1;
}
} else if (e.value == "HighToLow") {
console.log('sorted high to low');
if (a.price > b.price) {
return -1;
} else {
return 1;
}
}
});
setFilterData(sortedProducts);
};
return (
<div>
<select id="sortDropDown" onChange={(e) => sortItems(e.target)}>
<option value="default">Sort by:</option>
<option value="LowToHigh">Low to high</option>
<option value="HighToLow">High to low</option>
</select>
<select onChange={(e) => filter(e.target.value)}>
<option value="Filter Categories" selected="selected">Filter by categories</option>
{categories.map((catFilter) => (
<option value={catFilter}>{catFilter}</option>
))}
</select>
<select onChange={(e) => filter(e.target.value)}>
<option value="Filter Categories" selected="selected">Filter by brands</option>
{brands.map((item) => (
<option value={item}>{item}</option>
))}
</select>
<button onClick={filter}>Clear filter</button>
<div className='products'>
{filterData?.slice(0, productsLimit).map(product => (
<div className='product' key={product.id}>
<div className='productImage'>
<img src={product.thumbnail} />
</div>
<div className='productInfo'>
<div className='productTitle'>
<div className='productBrand'>{product.brand}</div>
<div className='productName'>{product.title}</div>
<div className='productName'>{product.title}</div>
</div>
<div className='productPrice'>Price: £{product.price}</div>
{}
</div>
</div>
))}
</div>
</div>
)
}
ReactDOM.render(<App />, document.querySelector('#root'));
.products {
display: flex;
flex-wrap: wrap;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>
您对 React 的理解不正确。请参考下面正确的方法。
// const [filterData, setFilterData] = useState(productDataList.products || []);
let [orderType,setOrderType] = useState("default")
let filterData = useMemo(()=>{
// write your order code with orderType ...
},[orderType])
return (
<select onChange={(e) => setOrderType(e.target)}>
<option value="default">Sort by:</option>
<option value="LowToHigh">Low to high</option>
<option value="HighToLow">High to low</option>
</select>
)
感谢@Robin Zigmond 的评论,为了更快地参考答案,我将其添加到这里。
更改 .sort
为 .toSorted
确实立即解决了问题。
const sortItems = (e) => {
console.log('Sort');
const sortedProducts = filterData.toSorted((a, b) => {
if (e.value == "LowToHigh") {
console.log('sorted low to high');
if (a.price < b.price) {
return -1;
} else {
return 1;
}
} else if (e.value == "HighToLow") {
console.log('sorted high to low');
if (a.price > b.price) {
return -1;
} else {
return 1;
}
}
});
setFilterData(sortedProducts);
};
其原因如下:
sort
改变数组并返回相同的引用(请参阅 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort ),因此 React 不会“看到”任何变化。如果您不需要支持一年前左右的浏览器,最简单的解决方案是使用新的toSorted
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/toSorted] 方法,而不是sort
我仍然认为适用于旧版浏览器的解决方案/解决方法会有所帮助,并且如果有添加的话我很乐意将其标记为答案,但现在感谢@Robin Zigmond 提供此解决方案。