Overview
This is a react-vite typescript project that fetches weather data from a free API (openweathermap.org). By default the page is set to the users location based on their approximate coordinates, which are fetched from ipapi (https://ipapi.co/json). The theme is set based on the set location, and whether or not the sun has set yet.
Experience gained
- Common React hooks
- Passing information throughout the react component hierarchy with props and functions
- Conditional rendering and styling
- Lazy loading with react suspense to optimize loading time
- Typescript: setting up interfaces, defining types, etc
- Async/await, fetch, promises
- Native javascript Date objects and associated methods
- Common javascript functions such as .map, .filter
- Node package manager and certain packages such as 'date-and-time'
- Environment Variables and testing/build configurations
- Bootstrap and CSS
- Parsing and custom sorting through data from API responses
Challenges
I faced various challenges throughout development that forced me to grow and think analytically.
1) Working with the API and optimizing the search component:
Early on I had to consider which of the various weather API to call, and how. The search bar functionality depended on this too.
I used a large object list provided by openweathermap containing all the cities in the world paired with their respective countries, IDs, and coordinates.
The file was big at first, so big that it would cause notable lag and long loading times for the page. I cut down the file size in half by removing white space, and the coordinate data
for each location. I further optimized the search bar component by having it load with React suspense.
The search bar would still take a few seconds to be ready on initial
load, but in the final build it was automatically optimized further to the point where it is now near instant.
The goal with the search bar was to display results dynamically as the user is typing. When the user selects a location, the value is set and gets passed to other components.
For the API calls, my solution involves conditionally building a URL string that fetches and updates both weather and forecast data, either with coordinates (on load/refresh), or
through a unique location ID from the large locations object. At some point I was struggling with useEffect and ensuring that the right components update and re-render at the right time, in parallel,
but after some modifications and conditional logic, I solved the issue.
2) Handling Response Data:
Another major challenge: dealing with the raw response data, especially for the forecast data.
Each response contains an array with 40 weather objects, that are not
already categorized by day. Each following array item represents forecast data 3 hours forward in time, relative to the previous. Each day has about 8 array[Obj] items which needed to be
sorted into another object containing 5 nested objects, one for each of the following 5 days, whose date values need to update dynamically. The date provided in
any given item from the list of 40 items, is either in the form of epoch time (seconds elapsed since epoch 1970 Jan 1 UTC+0), or in the form of a UTC date string, so this complicated things that much more.
The response object does not have a constant pattern/format to it, otherwise I could have just always taken the first 8 array items for example, and push them to the object representing tomorrow, within the
followingDays object. Anyway, I had to figure out how to convert the given epoch time to whatever the local time is in that location. This requires being considerate of both the
users current location (or what their browser date/time reports), their offset from UTC, and then the time zone offset of the selected location, then passing the final value in milliseconds to the outermost date object.
All of this was needed for both displaying the time for various things on the page, and for the initial process of iterating through the response array list, in order to
populate the "followingDays" object on each API query.
3) Conditional day and night styling/themes
My solution: Each time a location is selected, a check occurs that sets a useState boolean to true or false depending on the time of day, which is then
passed to the main 'App.tsx' react file. If the current time is after sunrise, but before sunset, the boolean is set to true and the day theme is used, otherwise the night time is used.
I couldn't
figure out how to conditionally import regular css files in the 'regular' way, so instead I came up with a different solution. For both themes, I took the contents of the original css files and stored them as lengthy string literals in separate tsx files.
The constants from those files are imported into app.tsx, and then only one is applied at a time as part of the style tags, based on the locations' current time. This is located within the main return statement of 'App.tsx'.