'How do I get useEffect to run on array sort? [duplicate]
I have an object like this
const example = [{medicineName : "Some name"
medicineId : 1}
{medicineName : "Some other name"
medicineId : 2}
]
const [filteredMedicineList, setFilteredMedicineList] = useState([]);
I map over filteredMedicineList
to produce some other DOM elements.
filteredMedicineList.map((data) => {
return <SingleMedicine data={data} key={data.medicineId} />;
})
Also on the page, I have some sort of button
that when clicked is supposed to sort the medicineList
in a particular order.
const compareFunction = (a, b) => {
if (a.medicineName < b.medicineName) {
return -1;
}
if (a.medicineName > b.medicineName) {
return -1;
}
return 0;
};
const handleSort = (sortBy) => {
filteredMedicineList.sort(compareFunction);
console.log("After sort");
console.log(arrayX);
};
My question is how do I get the sorted changes or results to reflect on the components that I mapped over. I cant use useEffect
because I believe useEffect
is when something changes and I am not sure anything here changes. Like in my example I want when the array is ordered in the order in which the <Singlemedicine/>
component is shown to also change.
Second Question. In my compareFunction()
that's just some code, I copy-pasted, I did not understand it. How is the equality checked in strings? Like how does javascript
determine that String "COW" is greater than "Carmel" is it by the length of the strings? Forgive a noob and then help
Solution 1:[1]
The following line changes the filteredMedicineList
directly and still React sees the old reference to the array which does not make trigger the React rerendering.
filteredMedicineList.sort(compareFunction);
You need to use setFilteredMedicineList
to make changes to it like below. This creates a new array reference with sorted items in a new array which triggers the rerendering.
setFilteredMedicineList((prevFilteredMedicineList) => {
const copyOfprevFilteredMedicineList = [...prevFilteredMedicineList];
copyOfprevFilteredMedicineList.sort(compareFunction);
return copyOfprevFilteredMedicineList;
});
Another issue is your compare function return -1
in the first two conditions it should also be corrected.
const example = [
{ medicineName: "Some name", medicineId: 1 },
{ medicineName: "Some other name", medicineId: 2 }
];
const App = () => {
const [filteredMedicineList, setFilteredMedicineList] = React.useState(example);
const compareFunction = (a, b) => {
if (a.medicineName < b.medicineName) {
return 1;
}
if (a.medicineName > b.medicineName) {
return -1;
}
return 0;
};
const handleSort = (sortBy) => {
setFilteredMedicineList((prevFilteredMedicineList) => {
const copyOfprevFilteredMedicineList = [...prevFilteredMedicineList];
copyOfprevFilteredMedicineList.sort(compareFunction);
return copyOfprevFilteredMedicineList;
});
};
return (
<div className="App">
<button onClick={handleSort}>SORT</button>
{filteredMedicineList.map(({ medicineName, medicineId }) => (
<div key={medicineId}>{medicineName}</div>
))}
</div>
);
}
ReactDOM.render(<App />, document.querySelector('.react'));
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div class='react'></div>
Solution 2:[2]
You have to use setState
to trigger a render. The array's reference should change and the component will rerender.
const handleSort = (sortBy) => {
filteredMedicineList.sort(compareFunction);
setFilteredMedicineList([...filteredMedicineList]);
console.log("After sort");
console.log(arrayX);
};
Regarding your second question, how cow is larger than camel is by comparing character one by one. C then O > C then A.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 |