Expo/React Native product catalog app using the Fake Store API.
- Product listing from
https://fakestoreapi.com/products. - Product details screen loaded from
https://fakestoreapi.com/products/:id. - Category filter loaded from
https://fakestoreapi.com/products/categories. - Category product listing loaded from
https://fakestoreapi.com/products/category/:category. - Product list with image, name, price, and category.
- Local search by product name, matching multiple terms in any order.
- Category filter loaded from the API.
- Product details with larger image, title, price, category, full description, rate, and count.
- Favorites add/remove action from the list and details screens.
- Visual favorite indication in product cards.
- Favorites screen with locally saved products.
- Favorites persistence with
@react-native-async-storage/async-storage. - Pull-to-refresh on the product list.
- Loading, empty, and retry/error states for the main API flows.
- Inline list loading when switching categories, keeping search and filters visible.
- Fallback UI for unavailable product images.
- Web support through React Native Web.
- Unit tests for search matching and favorites serialization.
- React Native
- Expo
- TypeScript
- React Navigation
- Axios
- AsyncStorage
- Fake Store API
- Node test runner with
tsxfor lightweight TypeScript tests
The source is organized by feature/domain:
src/features/products: product API, screens, hooks, components, and product types.src/features/favorites: favorites context, screen, and persistence.src/shared: reusable UI, theme tokens, and generic utilities.src/navigation: app stack/tab navigation and route types.src/api: shared API client setup.tests: unit tests organized outside the application source tree.
- Feature-first organization keeps product and favorite code close to their domain.
- Axios is centralized in a shared API client, while product endpoints live inside the products feature.
- Favorites are managed with React Context and persisted with AsyncStorage.
- Product search is local and split into independent terms, so searches like
TB WDstill match the product title. - Theme tokens centralize colors, radius, and shadows to avoid scattered styling values.
- Product image rendering is encapsulated in a reusable component with fallback UI.
- Category changes use an inline loading state instead of replacing the entire screen.
- Tests focus on logic that is easy to regress: search matching and favorites serialization.
FlatListis used for product and favorite lists.- Search filtering is memoized with
useMemo. - API loading callbacks are memoized with
useCallback. - Favorite IDs are stored in a memoized
Setfor quick favorite checks. - Pull-to-refresh reloads the current selected category instead of resetting the screen state.
- Selecting the already active category does not trigger another API request.
- Product image fallback avoids broken/blank image areas.
- TypeScript strict mode is enabled.
- The Fake Store API does not provide server-side search, so search is intentionally local over the products currently loaded.
- Favorites are stored only on the device; there is no account sync.
- The app depends on the availability and response shape of the public Fake Store API.
- The native Expo scripts run with
--offlineto avoid local Expo Go manifest signing failures in this environment.
Install dependencies:
yarn installStart Expo for Android/Expo Go:
yarn startOpen directly on a connected Android device/emulator:
yarn androidStart Expo Web:
yarn webRun TypeScript validation:
yarn typecheckRun unit tests:
yarn testThe native Expo scripts run with --offline to avoid development manifest signing calls to the Expo API during local testing. This prevents local Expo Go runs from failing with UnexpectedServerData: Unexpected server error: No returned query result when Expo's remote certificate query does not return data.
The web script includes EXPO_UNSTABLE_HEADLESS=1 to avoid launching the standalone React Native DevTools shell in environments where Chromium's sandbox helper is not configured.