My final project at Flatiron is an NFT (Non-Fungible Token) Drop Calendar that tracks the release of soon-to-be-dropped collectible NFT’s, allowing users to export drop events into their personal calendar and learn more about the NFT space in general. The application is built with a React/Redux frontend and a Rails API backend.
Drop event data for the calendar is currently user-generated, partly due to the last-minute nature of drop announcements and partly because there wasn’t a good NFT drop data source I was able to find. If you’re reading this and you have ideas on NFT drop data sources, please let me know!
It didn’t take long to recognize the benefits of React in terms of increased speed and efficiency afforded by the framework. In combination with Redux to limit the use of local state for individual components, the program flies when compared to my previous web-apps.
For this project, I tried my best to distinguish between presentational components and functional components. Since this is a project that I plan to expand on, I wanted to be sure that my components were as reusable as possible and made sure to spend extra time mapping out the structure. My intention was to keep all presentational components strictly responsible for the UI of the program (no functions or data handling in any way) and to keep the functional components dedicated to fetching and prepping data to pass down as props.
One thing that really tripped me up with this type of organization is that both types of components can render both functional and presentational components. With the use of Redux to manage global state, a functional component that is rendered by a presentational component doesn’t need to receive data through props, as it can be obtained through global state.
In case it’s helpful to anyone beginning their React journey, here’s the basic component breakdown of NFT drop calendar.
Index.js & App.js
If you’re starting off with
create-react-app then a lot of the basic setup is provided. Index will grab the HTML page and render the main App component on it. One modification that does reside inside in the Index file is connecting to Redux if you plan to use global state. I also imported Thunk, which mainly allows the program to track a ‘loading’ state — time that the platform is actively fetching or rendering data. Using that global loading state, the program renders a brief loading icon before rendering the data once loading has stopped. Double points if you can spot it in the demo video below!
The App component’s main responsibility is rendering the Navbar and defining which components should be rendered when different routes are hit using
react-router-dom. An important note regarding the Navbar is that it isn’t very obvious how to get your links to play nicely with React Bootstrap components. React Bootstrap’s documentation recommends using
<Nav.Link /> components, but react-router-dom requires
<NavLink /> components. After some testing (and failed redundant component wrapping), it dawned on me that React Bootstrap’s
<Nav.Link /> was really just adding styling to the link. Therefore, the fix was as easy as adding a regular bootstrap class (nav-link) to the component. When using React Bootstrap, I found there were so many instances where normal bootstrap was a better option for what I was trying to achieve.
The calendar container is the meat and potatoes of this application. This is the most functional container in the program, responsible for fetching event data from the API (stored in the global Redux state), rendering the child components SearchContainer and DaysContainer, creating filtering/sorting functions to pass through as props, and much more.
This container is responsible for all searching/filtering/finding that happens on the calendar. At first, the search container was a sibling of the calendar container rather than a child. However, in an effort to use event filtering/querying as a local state inside the calendar container, the search container needed to be a child so that filtering/querying functions could be passed down. This way, simple things like searching and filtering wouldn’t change the global state, triggering a complete re-render of the entire app.
The search container’s children include: the search input component and a filter container to manage quick filtering actions.
DaysContainer.js & Day.js
The duty of this container is to identify each unique day from the list of events to be displayed and categorize events by drop date. For each unique day that is included in our list, a <Day /> component is rendered, with props like ‘date’ and ‘events’ passed through. A table is created for each day, where each event for that day becomes a line item.
This presentational component is responsible for creating table cells for each relevant piece of drop data. Since all of the information is received via props from the parent, this component is purely rendering that data in a stylized manner. Another interesting note on using React Bootstrap is that table cells are not a fixed size by default, even if you manually set a colSpan. Some basic CSS is required to fix this:
Overall, I had a blast building the calendar and plan to expand on the tool as my skills continue to evolve in tandem with the NFT space. Features that weren’t able to be built this week include: combining filtering options, automatic data scraping/fetching for new drop announcements, an option to export/sync the entire calendar’s library of events, more information on creators’ previous projects, notifications for last minute drop announcements, and so much more! Here’s a link to the repo if you’d like to follow along (or join me!) and here’s the demo: