I’m learning React, I’m still a beginner and I’m encountering an issue while attempting to sort an array of objects in a React component. The error message I’m receiving is "Cannot read properties of undefined (reading ‘price’). This happen only when I use UseState, I tried not to use it and use the sorting’s comparison function directly let productsPrice = productData.sort((a, b) => a.price - b.price))
and it worked very well.
Code:
import '../style/products.css';
import productData from '../products-data';
import Product from './Product';
import { useState } from 'react';
function ProductsList() {
const compareAscendingPrice = (a, b) => a.price - b.price;
const compareAscendingRate = (a, b) => a.rating.rate - b.rating.rate;
const compareAscendingAlpha = (a, b) => a.title.localeCompare(b.title, 'en');
// let type = compareAscendingAlpha;
let [type, SetType] = useState(compareAscendingPrice); // useState hook
let productsPrice = productData.sort(type);
let products = [...productsPrice].map((item) => {
return <Product item={item} key={item.id} />;
});
return (
<>
<div className="products__filter">
<div className="products__filter__search">
<input type="text" placeholder="Search" />
</div>
<div className="products__filter__sort">
<label htmlFor="sort">Sort by:</label>
<select
name="sort"
id="sort"
onChange={(e) => {
if (e.target.value === 'price') {
SetType(compareAscendingPrice);
} else if (e.target.value === 'rating') {
SetType(compareAscendingRate);
} else if (e.target.value === 'title') {
SetType(compareAscendingAlpha);
}
}}
>
<option value="price">Price</option>
<option value="rating">Rating</option>
<option value="title">Title</option>
</select>
<div className="products__filter__direction">
<label htmlFor="ascending">Ascending</label>
<input type="checkbox" name="ascending" id="ascending" />
<label htmlFor="descending">Descending</label>
<input type="checkbox" name="descending" id="descending" />
</div>
</div>
</div>
<div className="products">{products}</div>;
</>
);
}
export default ProductsList;
What could be causing this issue, and how can I ensure that the price property is properly recognized during sorting?
I checked the data files, I looked on the internet, but I did not find any solution.
Note: I’m learning React I’m still a beginner.
2
Answers
You haven’t defined price in compareAscendingPrice arrow function. That’s the issue. First of all, you have to get the data from array!
There are two problems there (well, really two different versions of the same problem): Both
useState
itself and the state setter you get from it expect that when you pass a function into them, they’re supposed to call that function rather than store it. ForuseState
itself, it expects to call that function only during the initial mount (docs). For the state setter, it expects that you want to queue a state update callback (docs). You can’t directly store functions in state.You have at least a couple of alternatives:
Store a flag that you’ll then use to pass to a generalized sort function that knows which of those sort functions to call.
or
Store an object with the desired sort callback as a property.
Here’s an example of #1:
Then when setting it:
There I’ve used
e.target.value
directly by making the option values the keys of thecomparisons
object, but you could continue to use aswitch
if you preferred.(I changed
type
tosortType
to be more specific, and used an initial lower-case letter because by convention, functions with upper-case initial letters are constructor functions.)