I generate cards on a button press. These cards have a randomly generated number between 0 and 100. I am trying to setup a component or function that would allow me to sort all of these cards in numerical order ascending or descending, or both, when I click the sort button. I have tried the following code. Keep in mind, this is all contained within the same App component.
The random numbers are generated in the add card component.
I feel like I'm super close, but I can't figure out what I'm missing.
const sortTypes = {
up: {
class: "sort-up",
fn: (a, b) => a.number - b.number,
},
down: {
class: "sort-down",
fn: (a, b) => b.number - a.number,
},
default: {
class: "sort",
fn: (a, b) => a,
},
};
const sortAll = () => {
state = {
currentSort: 'default'
};
onSortChange = () => {
const { currentSort } = this.state;
let nextSort;
if (currentSort === 'down') nextSort = 'up';
else if (currentSort === 'up') nextSort = 'default';
else if (currentSort === 'default') nextSort = 'down';
this.setState({
currentSort: nextSort
});
};
};
return (
<body>
<header>
<div className="ui buttons">
<button type="button" onClick={addCard} className="ui button mb-1 mt-1 mr-1"><i className="plus icon"></i>Add Card</button>
<div className="or mb-1 mt-1"></div>
<button type="button" onClick={sortAll} className="ui positive button mb-1 mt-1 mr-1"><i className="redo icon"></i>Sort All</button>
</div>
</header>
this
to reference.onSortChange
is the button onClick
handler you want to use to update the current sort.Move the currentSort
to component state in a useState
hook.
const [currentSort, setCurrentSort] = useState("default");
Fix the onSortChange
handler to correctly update state.
const onSortChange = () => {
let nextSort;
if (currentSort === "down") nextSort = "up";
else if (currentSort === "up") nextSort = "default";
else if (currentSort === "default") nextSort = "down";
setCurrentSort(nextSort);
};
Use an in-line "sort" in the render return. Remember that array.prototype.sort
is an in-place sort, i.e. it mutates the array. To get around accidentally mutating state first copy the array.
{cards
.slice() // <-- copy
.sort(sortTypes[currentSort].fn) // <-- select sort function
.map((cardNumber, index) => (
<MainCard
number={cardNumber.number}
key={cardNumber.id}
onRemove={() => removeCard(cardNumber.id)}
/>
))}
Attach correct handler to button
<button
type="button"
onClick={onSortChange}
className="ui positive button mb-1 mt-1 mr-1"
>
<i className="redo icon"></i>Sort All
</button>
Full Code:
const generateId = (seed = 0) => () => seed++;
const getRandomNumber = function (min, max) {
let getRandom = Math.floor(Math.random() * max + min);
return getRandom;
};
const sortTypes = {
up: {
class: "sort-up",
fn: (a, b) => a.number - b.number
},
down: {
class: "sort-down",
fn: (a, b) => b.number - a.number
},
default: {
class: "sort",
fn: (a, b) => a
}
};
const MainCard = ({ number, onRemove }) => {
return (
<div className="card">
<button
onClick={onRemove}
className="ui mini red basic icon button"
style={{
position: "absolute",
top: "0",
right: "0"
}}
>
X
</button>
{number}
</div>
);
};
export default function App() {
const [cards, setCards] = useState([]);
const [currentSort, setCurrentSort] = useState("default");
const addCard = () => {
setCards((cards) => [
...cards,
{
id: generateId(),
number: getRandomNumber(0, 101)
}
]);
};
const removeCard = (id) => {
setCards((cards) => cards.filter((el) => el.id !== id));
};
const onSortChange = () => {
let nextSort;
if (currentSort === "down") nextSort = "up";
else if (currentSort === "up") nextSort = "default";
else if (currentSort === "default") nextSort = "down";
setCurrentSort(nextSort);
};
return (
<body>
<header>
<div className="ui buttons">
<button
type="button"
onClick={addCard}
className="ui button mb-1 mt-1 mr-1"
>
<i className="plus icon"></i>Add Card
</button>
<div className="or mb-1 mt-1"></div>
<button
type="button"
onClick={onSortChange}
className="ui positive button mb-1 mt-1 mr-1"
>
<i className="redo icon"></i>Sort All
</button>
</div>
</header>
<div className="card-container">
{cards
.slice()
.sort(sortTypes[currentSort].fn)
.map((cardNumber) => (
<MainCard
number={cardNumber.number}
key={cardNumber.id}
onRemove={() => removeCard(cardNumber.id)}
/>
))}
</div>
<aside className="showHide"></aside>
<footer>
<h3 className="text-center text-muted">Footer</h3>
</footer>
</body>
);
}