Solution for a challenge from Devchallenges.io.
This application/site was created as a submission to a DevChallenges challenge. The challenge was to build an application to complete the given user stories. Note: The previous design document may be incomplete, as you need to find an archived version of the challenge as all legacy
challenges have had their documentation removed from DevChallenges.
- I can search for cat breeds and select a breed of my choice
- I can see the most popular searched cat breeds summary on the homepage
- I can see the top 10 most searched cat breeds
- I can see the breed details including description, temperament, origin, life span, adaptability, affection level, child-friendly, grooming, intelligence, health issues, social needs, stranger friendly
- I can see more photo of the breed
- On mobile, when I select the search option, a modal for breed search should pop up
- I can go to an article about cats when I click read more on Why you should have a cat section
- I can go to the top 10 cats by clicking see more in the dashboard
- DevChallenges did not add a design for two pages: the breeds index page and the
why you should have a cat
page. - You can't search for multiple breeds at once on the API. You have to use a promise.all() / multiple fetches to get each breed needed, i.e.
/breeds/search?q=beng
. - You can get 4 random images with image search and the limit parameter, but it is random, and some pictures don't make sense for the design. Plus, image search gives you no idea of the breed etc.
- Image component has a lot of quirks and things to be mindful of. Responsive image optimization is a nightmare. It shouldn't be this unclear to do things that are extremely easy to do in basic HTML code. Adding a srcSet to the Image component is not really covered. Having multiple images is not really necessary with the Image component. So do you use the largest image exclusively? Next does scale down. Can it scale up from a medium-sized image?
- There have been many updates to Next Image since I first did this challenge. I need to investigate more to better optimize images in the app.
- I used layout="responsive", and under tablet sizes, the background became too small when there was more space available. You have to set image sizes in the config for device sizes that are not default values.
- You have to worry about duplicate pictures in the other images section.
Aegean
has the same picture with different IDs, which shows up in the other images section.- You can use a ref to try and prevent the label from overlapping the text of the input on blur.
- I fixed overlapping by using a valid pseudo-selector on the input in the css.
- Using a layout page caused styling issues. The minimum height is
100 vh
inglobals.css
, but it seems not to have been applied as the benefits page's footer was not at the bottom of the page. - There is a problem with the European Burmese detail page. The breed doesn't have a
reference_image_id
. The API request for the image fails and this prevents the page from showing any content. Since I am using fetch, the error handling is not as easy or as clean to implement. - Originally, the
Read More
andSee More
links were paragraph tags inside theLink
element. I changed them to buttons so they can be tabbable. Similarly, I added buttons to breeds list page so they can easily be tabbed through as well. - However, this is problematic as having a button inside an
<a>
tag is illegal in HTML5. You need to addbaseHref={true}
to the<Link>
tag so the links will be tabbable. See Github for more. - When I converted from Next 12 to Next 14, Image had the most breaking changes. I decided to stick with the legacy image implementation.
images.domains
was deprecated. I replaced it withimages.remotePatterns
.- The cat API documentation has improved since I first tackled this challenge. I could look more into a voting system and the favoriting of breeds. Doing it may require logins or a local storage cookie to prevent a single user from voting excessively.
- Next 14 supports Node 16 until early 2024 and then you will need Node 18.
- I decided not to add TypeScript when converting to App Router.
- I followed this guide to convert to App Router.
- Without adding a head.js file, can you change the favicon? Yes. Next will look for files that start with
icon
,favicon
, orapple-icon
in the app folder. - When copying pages over to the app router, it is best to name them slightly different. This allows you to keep your original page, as naming conflicts will prevent the app from running.
- You can't utilize useSearchParams with server-side data loading.
- This means you have to add 'use client' and use a useEffect to load data with the
searchTerm
. - This is a lose-lose situation as useEffect is slower for data fetching, and you have to worry about memory leaks and possibly add a cleanup function. Adding abort controllers with multiple requests is more involved with less documentation available.
- You need to add
React Suspense
when using useSearchParams. Next will throw an error before your state and page updates. - I incrementally added all pages to the app router. I deleted the
pages/_app.js
file and the remaining breed page did not have the correct styling and layout. It is important to keep yourpages/_app.js
file whenever you are using any page files. - I needed to use
encodeURI
on the breed names inside theLink
hrefs. Spaces are not allowed inside a link's href. - Prior to the Next 14 conversion, I checked for duplicate pictures in the extra images grid. I have not done that here. Ultimately, even if you perform a filter to exclude duplicate file names, the API database has entries of the same photo with a different file name. I documented this issue in my Angular conversion of this project.
- The breed detail page was deopted and used the client to fetch the data. This may expose the API key. I looked in the devtools and the
x-api-key
was undefined for the API requests. This error was caused by an incorrect placement of React Suspense. Suspense is needed when you adduseSearchParams
. I think the Suspense needs to wrap a component function and not just JSX. - I had the Suspense inside a
main
tag. Suspense probably needs to be the outermost element in its component. The fallback displays very briefly. Even on slow 3G, the loading text was barely there. It seems like you only see the Fallback when you run the build version of the app. - The
breeds.module.css
was preloaded, but it was not used by the breed page. - Link component preloads CSS modules and this causes a warning in the console. If there are many Link tags, the browser console will be flooded. This is very annoying. If you add
prefetch={false}
to the Link tag, the warning will go away. Performance implications? I didn't notice much of a difference. - App router seems to have a very loose CSS structure. You can colocate CSS anywhere. I am not really a fan of this and I preferred using a styles folder. In my conversion, I left the original styles folder and I still have it for now. I could move the component styles into the components folder or I could just add the files to the base app folder.
- Link's default styling throws off my header's styling. I used the same html as my Angular conversion and just changed the a tags to Link tags and the CSS was off.
- Header and Footer components have limited styling so I initially added those styles to
global.css
. I have since removed those styles and added a Footer module while adding the Header's styling inline. - Testing Next 14's App Router is uncharted territory. It is tough to decide on an approach that works. I think E2E testing is further along than unit testing.
- Next testing documentation is not done.
- MSW works with client side pages, but does not work with server rendered pages. See Github for more.
- Investigate catapi changes
- API error handling improvements
- Typescript ?
- Testing
- Better dynamic page title implementation
- Filter duplicate image entries from the Breed page
- Suspense issues
- Header styling issues on screens smaller than 425px & various other CSS issues
To clone and run this application, you'll need Git and Node.js (v18+) (which comes with npm) installed on your computer. From your command line:
# Clone this repository
$ git clone https://github.com/jdegand/devchallenges-cat-wiki.git
# Install dependencies
$ npm install
# Before you run the app
# disable telemetry with `npx next telemetry disable` command
# Add .env.local with API_KEY from thecatapi
# Run the app and navigate to localhost:3000
$ npm run dev
- Steps to replicate a design with only HTML and CSS
- YouTube - Next Image Optimization
- YouTube - Next Background Image
- Next JS Demo - Image for background
- Stack Overflow - next background image
- Medium - staggered css grids
- Codepen - staggered grid
- Stack Overflow - next image component to 100% height
- YouTube - move placeholder text on focus
- Codepen - floating placeholder
- Codepen - search modal
- YouTube - search modal
- DelftStack - filtering with multiple values
- Stack Overflow - find multiple objects by id
- Next Docs - next image unconfigured host
- Stack Overflow - pass data to link component?
- Kinda Code - passing data via a link component
- Stack Overflow - multiple fetch requests with getServerSideProps
- PluralSight - nested http requests using fetch api
- Stack Overflow - access previous results in a promise chain
- YouTube - promise chaining
- Log Rocket - promise chaining is dead
- Stack Overflow - next & picture element
- Forum - fetch multiple images per breed (limit required?)
- Stack Overflow - unique values in array
- Help Guide - joys of owning a cat
- The Spruce Pets - top mistakes of cat owners
- Berkeley - science backed benefits
- Digital Ocean - conditional rendering in react
- YouTube - search modal in vanilla js
- Stack Overflow - detect if an input has text in it
- Stack Overflow - nextjs background image
- Github - next image problems
- YouTube - aspect ratio and responsive next images
- Github - next image priority issues
- UploadCare - next js images optimization pros and cons
- Dev.to - responsive fix for next js (need a wrapper?)
- YouTube - explicit width and height error in nextjs
- Stack Overflow - more style name with css modules
- Stack Overflow - customize scollbar
- Next - next image upgrade to 13
- Next - image legacy priority
- Github - theCatApi website
- Github - theCatApi examples
- YouTube - Incrementally adopt the Next.js App Router
- Reddit - what is the correct way to handle errors inside getServerSideProps
- Next - get server side props redirect
- Next - useRouter
- FreeCodeCamp - fetch chain
- Reddit - app router is not production ready yet
- Stack Overflow - how to apply global css styles to pages folder in next 13
- Stack Overflow - multiple fetch in useEffect fetch data depend on another fetch data
- Next - data fetching patterns
- Stack Overflow - can I nest a button element element inside an a tag using HTML5?
- Github - next link tag accessibility concerns
- MDN Docs - encodeURI
- Github - How to set page title and description if page is "use client" ? #50872
- Github - Non-NextJS Error Boundary doesn't catch errors originating from server components.
- Next - security nextjs server components actions
- Stack Overflow - suspense fallback is not showing in next 13 when navigate by useRouter
- Github - Navigation changing just searchParams doesn't trigger loading.tsx
- Github - How to fix link preload warning in Next.js app?
- Github - Suspense only shows its fallback once (on page load), when async component suspends, the Suspense wrapper doesn't fall back. All components working however
- Github - useRouter mocking
- Github - mock
next/navigation