React Native app that lists the 127 Dota 2 heroes from the OpenDota API and shows a full hero profile (stats, attributes and abilities) from Valve's Dota 2 data.
- Home — searchable roster in a two-column grid
- Explore — same roster filtered by primary attribute and role
- Spotlight — hero of the day with stats, hype quote and lore
- Hero detail — attributes, combat stats and abilities with icons
- Settings — data sources, cache controls and app info
Captured on the iPhone 18 Pro simulator (iOS 27). Regenerate them with
scripts/screenshots.sh (booted simulator + yarn ios); the process is
documented in docs/screenshots.md.
- React Native 0.87 (New Architecture), React 19, TypeScript
- React Navigation 7 (bottom tabs + native stack)
- TanStack Query for server state
- InversifyJS +
reflect-metadatafor dependency injection - LegendList for the heroes lists
- Ionicons (
@react-native-vector-icons/ionicons), Axios, Jest, ESLint, Prettier
Hero and ability images are loaded from Valve's Steam CDN (cdn.cloudflare.steamstatic.com).
Requirements: Node >= 22.11, Yarn 1, JDK 17 + Android SDK (Android), Xcode + CocoaPods (iOS, macOS only).
yarn install
# iOS
cd ios && bundle install && bundle exec pod install && cd ..
yarn ios
# Android
yarn androidyarn start runs Metro on its own if you launch the app from Android Studio / Xcode.
| Command | Description |
|---|---|
yarn start |
Start Metro |
yarn android / yarn ios |
Build and run on an emulator/simulator or device |
yarn test |
Run Jest |
yarn lint |
Run ESLint |
npx tsc --noEmit |
Type-check |
scripts/screenshots.sh |
Recapture the README screenshots on the iOS simulator |
Clean Architecture with an InversifyJS container (reflect-metadata + legacy decorators via Babel):
src/
domain/ entities, repository interfaces, use cases (no framework imports)
data/ DTOs, mappers, data sources, repository implementations
infrastructure/ HttpClient (axios)
core/di/ TYPES tokens, ContainerModules, container, DIProvider/useInjection
core/query/ TanStack Query client (refetch when the app returns to foreground)
presentation/ screens (Home, Explore, Spotlight, Settings, HeroDetail), navigation, components, hooks, theme
Dependencies point inwards: presentation -> domain <- data -> infrastructure.
HomeScreen -> useHeroes -> useQuery -> GetHeroesUseCase -> HeroRepository -> HeroRemoteDataSource -> HttpClient
HeroDetailScreen -> useHeroDetails -> GetHeroDetailsUseCase -> ...
Bindings live in src/core/di/modules.ts. Components resolve use cases with useInjection(TYPES.X) and call them from TanStack Query hooks; tests can container.rebind(...) any dependency with a fake.
- Add the entity, repository interface and use case in
src/domain. - Implement the data source / repository in
src/data(map API DTOs to entities insrc/data/mappers). - Add tokens in
src/core/di/types.tsand bind them insrc/core/di/modules.ts. - Expose it to screens through a hook in
src/presentation/hooksusinguseQuery/useMutation.
Remove the window shadow from macOS screenshots:
defaults write com.apple.screencapture disable-shadow -bool TRUE; killall SystemUIServer



