The packageManager is set to pnpm in the package.json file but you can use npm or yarn as well.
pnpm installpnpm start/app- contains the different routes of the app, usingexpo-routerto handle navigation./components- shared components that can be used in multiple parts of the app./constants- constants for colors, font sizes and spacings./hooks- custom hooks used in the app./types- TypeScript types used in the app.
The UI is quite colorful because I first generated the icon of the app with an AI and I used it as an inspiration. I had recently seen a video about linear gradients in React Native and wanted to try it out. I avoided using any UI library to follow the requirements.
The book details screen does not fetch its own data for two main reasons:
-
No need for fresh data: The book details are unlikely to change frequently, and we've already fetched this data when displaying the search results. Reusing this data avoids unnecessary network requests.
-
No deep linking requirement: Since we don't need to support deep linking to this screen, we don't need to handle scenarios where a user might directly access a book's details without going through the search process.
Instead, we pass the book data through the global state managed by Zustand.
I chose to use Expo Router to try their file based routing. It is probably overkill for this simple app.
I used Zustand to manage the state of the app because it offers a simple and performant API. Persistence is managed with async-storage.
I used Shopify'sFlashList for the list of books to have a smoother experience with the infinite scroll.
I used Moti for the shimmer effect on the placeholder of the book cards. It was mainly to try out this library of your tech stack.
- The custom font for the subtitle of the app only works in a development build, not in Expo Go.
- I wrote the tests in the end and lacked time so I focused on some critical components and one screen. I followed the suggested structure of expo to have a root
__tests__folder with the test files. With more time, I would add some more tests and try to mock the API calls rather than the hooks. - The Search is kept as an uncontrolled text input because there are known performance issues with controlled inputs in React Native, some even argue they are broken
langRestrict: 'en'parameter in the API call: this is because the Google BooksAPI seems to determine the language based on the IP of the client and return results in dutch by default.- I tried (a bit late) to follow the advice of the Google Books API to use the
fieldsparameter to limit the amount of data being sent over the network. But it broke the pagination logic so I removed it by lack of time to make both work. - Code could probably be more DRY. WishlistButton and ReadingListButton should probably be merged.
- With the file-based routing, I wasn't too sure how to organize the components folder.
- I used react-native-dotenv to manage the API key but I ended up removing it and using process.env directly because it crashed the app entirely on my second computer.