Historical places exploration app built with Expo and React Native.
Since this project uses native code, you need a Mac with Xcode installed to run the iOS build.
npx expo run:ios- Ensures you have CocoaPods installed (
sudo gem install cocoapods).
You can run the Android app on a connected device or emulator.
npx expo run:android- Requires Android Studio and SDK installed.
We support deep linking to specific screens (e.g., details page).
You can test deep links directly from your terminal using uri-scheme:
Android:
npx uri-scheme open test://details/201 --androidiOS:
npx uri-scheme open test://details/201 --ios- Start the App: Ensure the app is running on your simulator or device.
- Transfer File: Send the
test_deep_linking.htmlfile to your mobile device (or open it on your simulator's browser). - Open & Click: Open the file in your mobile browser and click the links.
- "Open Details (ID: 201)": Opens the details screen for place ID 201.
- "Open App Home": Opens the main feed.
This project uses Expo Router (file-based routing) located in the app/ directory.
- screens: Files in
app/become screens automatically. - navigation:
_layout.tsxfiles define navigation stacks (e.g., Native Stack). - dynamic routes: Folders like
details/[id].tsxhandle dynamic parameters.
app/: Screens and Navigation headers.src/components/: Reusable UI components.src/store/: Redux state management.src/types/: TypeScript definitions.
We use Redux Toolkit (RTK) for global state management, enhanced with Redux Persist for data longevity.
We deliberately chose RTK Query over redux-observable (RxJS Epics) for the following reasons:
- Simplified Data Fetching: RTK Query is purpose-built for data fetching and caching. It handles loading states, error handling, and caching out-of-the-box, significantly reducing boilerplate code compared to writing custom Epics for every API call.
- Maintainability & Focus: While RxJS is powerful for complex event streams, for standard REST API interactions, RTK Query provides a more streamlined and maintainable solution that keeps the codebase focused on business logic rather than stream orchestration.
- Built-in Best Practices: RTK Query automatically handles deduping requests, optimistic updates, and cache invalidation, which would require manual implementation with Epics.
- Modern Redux Standard: It is the officially recommended approach by the Redux team for async logic.
To ensure user data (like visited places) remains available after the app is closed, we use Redux Persist with MMKV.
We use react-native-mmkv as the storage engine because:
- Speed: It is significantly faster than standard
AsyncStoragebecause it uses a direct C++ binding to a memory-mapped key-value store. - Synchronous Execution: Operations are synchronous, avoiding the overhead of async bridge calls.
- Reliability: It is widely used in high-performance production applications.
- Storage Wrapper: See
store/mmkv-storage.tsfor the Redux Persist compatible wrapper. - Persisted Slices: The
placesslice is currently configured for persistence instore/index.ts.