Core infrastructure for React Native applications, providing the basics to avoid repeating yourself when bootstrapping a new app.
Core infrastructure for React Native applications, providing a robust foundation for subscription management and state persistence.
- RevenueCat Integration: Seamless wrapper around react-native-purchases.
- Subscription Store: Powered by Zustand and MMKV for high-performance persistence.
- Type Safety: Built with strict TypeScript rules.
``sh`
npm install react-native-nucleus react-native-purchases zustand react-native-mmkv @react-native-community/netinfoor
yarn add react-native-nucleus react-native-purchases zustand react-native-mmkv @react-native-community/netinfo
Wrap your application with AppCoreProvider.
`tsx
import { AppCoreProvider, NucleusConfig } from 'react-native-nucleus';
import * as appTranslations from './locales/translations';
// Best practice: Derive supported languages from your translations object
const supportedLanguages = Object.keys(appTranslations) as (keyof typeof appTranslations)[];
const config: NucleusConfig = {
revenueCat: {
iosApiKey: 'your_ios_key',
androidApiKey: 'your_android_key',
// Required: Triggered when the paywall flow is finished (success, error, or cancel)
onPaywallFlowEnd: () => {
// e.g., router.push('/home') or closing a modal
console.log('Paywall flow finished');
},
},
};
export default function App() {
return (
);
}
`
Nucleus provides two hooks to access the same global store, allowing for better semantic clarity in your components:
- useAppCoreStore: General access to the entire state (isPro, language, etc).
> Important: Always use specific selectors to avoid unnecessary re-renders.
#### Accessing Subscription State
`tsx
import { useAppCoreStore } from 'react-native-nucleus';
const MyComponent = () => {
// Use a selector to only subscribe to isPro changes
const isPro = useAppCoreStore((state) => state.isPro);
if (isPro) {
return
}
return
};
`
#### Managing Language
`tsx
import { useAppCoreStore } from 'react-native-nucleus';
const LanguageSwitcher = () => {
const language = useAppCoreStore((state) => state.language);
const { setLanguage } = useAppCoreStore.getState();
return (
title={Current: ${language}. Change to PT} `
onPress={() => setLanguage('pt')}
/>
);
};
Use the purchaseService to handle purchases and restorations imperatively.
`tsx
import { purchaseService } from 'react-native-nucleus';
const restore = async () => {
try {
// Automatically updates the store state on success
await purchaseService.restorePurchases();
} catch (error) {
console.error(error);
}
};
`
To use RevenueCat's Paywalls and Customer Center, you need to install react-native-purchases-ui.
`sh`
npm install react-native-purchases-ui
Then you can use the built-in methods in purchaseService:
`tsx
import { purchaseService } from 'react-native-nucleus';
// Present Paywall (returns true if purchased/restored)
// Note: This also triggers the global onPaywallFlowEnd callback if configured
const showPaywall = async () => {
const purchased = await purchaseService.presentPaywall();
if (purchased) {
console.log('User is now Pro!');
}
};
// Present Customer Center
const showCustomerCenter = async () => {
await purchaseService.presentCustomerCenter();
};
`
| Property | Type | Description |
| :--- | :--- | :--- |
| revenueCat.iosApiKey | string | RevenueCat API Key for iOS |revenueCat.androidApiKey
| | string | RevenueCat API Key for Android |revenueCat.onPaywallFlowEnd
| | () => void | Callback triggered when paywall flow finishes (success, error, or cancel) |`
When testing components that use react-native-nucleus, you should mock the store and services.
`javascript``
jest.mock('react-native-nucleus', () => ({
useAppCoreStore: (selector) =>
selector({
isPro: true,
language: 'en',
setIsPro: jest.fn(),
setLanguage: jest.fn(),
resetSubscription: jest.fn(),
}),
purchaseService: {
restorePurchases: jest.fn(),
purchasePackage: jest.fn(),
},
}));
- Store: Zustand with MMKV persistence.
- Services: Singleton classes for external integrations.