I’m currently working with a card list in my MERN stack application that can sort cards by migration pattern and whether the current user has liked them or not. The sorting works with no issue, but when initially clicking an option that has no cards in it, while the sorting completes, the select bar jumps back to the default option which makes the user unable to pick the default option again until selecting another option.
For example…
My select bar looks like this:
const MigrationSelect = ({ handleSelectChange }) => {
return (
<div>
<div className="sort-container">
<label htmlFor="migration-pattern-select">
Sort by Migration Pattern:
</label>
<select id="migration-pattern-select" onChange={handleSelectChange}>
<option value="">All</option>
<option value="New Zealand to Alaska">New Zealand to Alaska</option>
<option value="Arctic to Antarctic and Back">
Arctic to Antarctic and Back
</option>
<option value="Eastern United States to Central America">
Eastern United States to Central America
</option>
//...continued with more options//
If the user selects "Arctic to Antarctic and Back" and no cards currently have that migration pattern, then sorting completes and the text "No birds currently on this path!" shows on the page, which is correct.
The problem is that when the page starts from the default option "All" and then there are no cards present in the selected option, the select bar immediately jumps back to the default option "All". It does not re-sort to "All" when it does this, but hides the text of the current selected option, "Arctic to Antarctic and Back", and makes it so that the user cannot click "All" to view all cards until they click another option.
If another empty option is clicked immediately following the first empty option, then that option’s selection stays in the select bar without jumping to the default option "All".
For example, if I click "Arctic to Antarctic and Back" and it is currently empty, the select bar text jumps back to "All". If I then click the "New Zealand to Alaska" option, and it also has no cards, the select bar text then stays as "New Zealand to Alaska" and it still properly sorts and displays the "No birds currently on this path!" text.
The user list component that handles the sorting looks like this:
import React, { useState } from "react";
import { Link } from "react-router-dom";
import { useQuery } from "@apollo/client";
import { QUERY_USERS } from "../../utils/queries";
import Card from "../Card/Card";
import MigrationSelect from "../MigrationSelect";
import AuthService from "../../utils/auth";
const UserList = () => {
const { loading, error, data } = useQuery(QUERY_USERS);
const [selectedPattern, setSelectedPattern] = useState("");
const [showLikedBirds, setShowLikedBirds] = useState(false);
const loggedInUserLikes = AuthService.getUserLikes();
if (loading) return <p>Loading...</p>;
if (error) return <p>Error: {error.message}</p>;
const handleSelectChange = (event) => {
setSelectedPattern(event.target.value);
};
const handleLikedBirdsButtonClick = () => {
setShowLikedBirds(!showLikedBirds);
};
const filteredUsers = selectedPattern
? data.users.filter((user) => user.migration === selectedPattern)
: data.users;
let sortedUsers = [...filteredUsers].sort((a, b) => {
const nameA = a.birdname.toUpperCase();
const nameB = b.birdname.toUpperCase();
if (nameA < nameB) {
return -1;
}
if (nameA > nameB) {
return 1;
}
return 0;
});
if (showLikedBirds) {
sortedUsers = sortedUsers.filter((user) =>
loggedInUserLikes.some((likedUser) => likedUser._id === user._id)
);
}
if (sortedUsers.length === 0) {
return (
<>
<MigrationSelect handleSelectChange={handleSelectChange} />
<button className="liked-button" onClick={handleLikedBirdsButtonClick}>
{showLikedBirds ? "Show All Birds" : "Show Liked Birds"}
</button>
<h2>No birds currently on this path!</h2>
{loggedInUserLikes === null ||
(loggedInUserLikes.length === 0 && (
<h2>You haven't liked any birds yet!</h2>
))}
</>
);
}
return (
<>
<div className="dash-sorting">
<MigrationSelect handleSelectChange={handleSelectChange} />
<button className="liked-button" onClick={handleLikedBirdsButtonClick}>
{showLikedBirds ? "Show All Birds" : "Show Liked Birds"}
</button>
</div>
<div className="card-container">
<div className="card-list">
{sortedUsers.map((user) => (
<Link to={`/bird/${user._id}`} key={user._id}>
<Card user={user} key={user._id} />
</Link>
))}
</div>
</div>
</>
);
};
export default UserList;
I’ve tried adding event.preventDefault();
to my handleSelectChange but the bug still happens.
I’ve console logged selectedPattern to ensure that, even when the select bar jumps back to the default option, the selectedPattern’s value remains true for the clicked option and never reverts back to the default value’s option. It is true that the selectedPattern’s value always stays the clicked option, even when the select bar jumps back to the default option
I’ve also temporarily commented out the extra sorting of liked birds to make sure that it wasn’t interfering in any way that caused the bug. The bug was still present after temporarily removing the liked birds sorting.
Thank you for any help you can provide!
>Solution :
You need to set the selectedValue inside your select tag.
<MigrationSelect handleSelectChange={handleSelectChange} />
should be
<MigrationSelect selectedValue={selectedPattern} handleSelectChange={handleSelectChange} />
Then,
const MigrationSelect = ({ selectedValue, handleSelectChange }) => {
Lastly,
<select id="migration-pattern-select" value={selectedValue} onChange={handleSelectChange}>