A popular feature in basic web applications is the functionality of selecting a specific item from a larger group of items and moving the selected item to another page or list. For example, on a shoe store website, a user can select a pair of shoes from a list of shoes on the homepage, and add that pair of shoes to their cart.
This functionality was a main feature in the React web application I created for my second project in my software engineering bootcamp. I decided to write a "how to" blog post on how to build out this functionality.
A little background on my project: I wanted to build a web application/database that displayed and organized ski resorts in the United States and Canada. I specifically wanted to "favorite" a ski resort and see that "favorited" ski resort in my Favorites page. I also wanted to add functionality to remove that ski resort from the Favorites page by "unfavoriting" the resort.
I created my own db.json with the top 135 ski resorts in the US and Canada. There is a specific key:value pair in my ski resort object dedicated to "favorite". The value of the "favorite" key is defaulted to "false" meaning the ski resort is not a favorite of the user. This key:value pair is a boolean because I wanted the boolean to switch to true once the user "favorited" the ski resort. Furthermore, a boolean easily allowed me to insert conditional rendering later in my code.
Note: I wanted the favorite/unfavorite functionality to persist when the webpage reloads. Therefore, a boolean for the favorite/unfavorite feature was required in the database, as well as a PATCH request (discussed later) was needed to update the database.
I separated my React components as follows:
**Disclaimer:* It's best practice to avoid duplicative components in React, however, at the time of publishing this blog post, I hadn't yet refactored my code, so there are duplicative components.
The ResortCard component was the component I rendered in both the ResortList and Favorites components. This allowed me to "move" each individual Resort Card between the Resort List page and the Favorites page.
In the App component, I set state for all of the resorts via the useState hook and then used the useEffect hook for a GET request to fetch my data from my db.json. I then passed "resorts" down as a prop to both the ResortList and Favorites components.
Note: For now, ignore the lines 19-29 and the onFavoriteResort prop - this function will be discussed later!
In the ResortList component, I mapped over the resort prop I sent down from the App component, and returned a ResortCard for each resort from the original array. Because each resort is an object, a key prop was added.
In the Favorite Component, I filtered over each resort and returned the "favorite" key:value pair. I targeted this key:value pair because it holds the boolean of whether the user has favorited the specific resort. I then mapped over that array and returned the same ResortCard. Once again, a key prop was added.
In the ResortCard component, I first destructured the resort prop that was originally passed from the App component through the ResortList and Favorite components (line 6). I then added each prop to the card (line 26-51) so the resort data would populate the card.
Once each card was made for each resort, I focused on the "favorite/unfavorite" functionality:
- State was set for favorite element, and "favorite" key:value pair of the resort object was set in the useState hook because I want the boolean value to reflect the DOM's state.
- I then set up my PATCH request within the handleFavoritedChange function, which first changed the favorite state of the resort to the opposite boolean value that was in the database (ex: in the database, the boolean is false, it would then be change to true) (line 13).
- Then in line 19, the database was updated to reflect the state of the ResortCard. This PATCH request function was connected to an onClick event listener, so when the empty star icon was clicked/unclicked, the handleFavoriteChange function would run.
- In line 22, the callback function "onFavoritedResort" was called. This callback function updates the DOM, so when the star icon is clicked to "favorite" a resort, that resort card is moved to the Favorite Page. And when a resort card is "unfavorited", the resort card leaves the Favorite Page.
- handleFavoritedResort callback function was passed down through ResortList and Favorites components from the App Component (I promised this function would be important!) handleFavoriteResort function lives in the App component:
- handleFavoriteResort function returns a new array which mapped over the original resort array. If the id of the favorited resort matches the resort id, then that resort is moved the updated array. The updated array (that contains the favorited resorts) is the parameter to the setResort setter function.
Note:I added some conditional rendering via ternary operator to my onClick button (line 29-37), so the star icon would be filled in when the resort card was favorited, and an empty star would appear when a resort was unfavorited.
The favorite/unfavorite functionality has now been built out! Here's how this functionality works:
When Alyseka Resort is unfavorited, the resort card is removed from the Favorites page, but still appears in the All Resorts page.
I started learning React 3 weeks ago, so the feeling of excitement and accomplishment when figuring out this functionality is the reason why I am so passionate about coding and software development. This functionality was one of the first major examples of being able to implement one of my ideas into a workable feature.
The favorite/unfavorite functionality can be used in many different scenarios, so I hope this tutorial was helpful!
As always, there are infinite ways to code, so I am sure there are many other ways to create this function. Please let me know if there are areas where I can improve my code!