Skip to content

[📚][Documentation][Guide] Implementing the New Modular Remote Config API - Remote Config (v23.x.x+) #8852

@felipemengatto

Description

@felipemengatto

Sorry for dumping this here, but I had a bit of a rough time getting the initial implementation right and figured others might be struggling too. I wanted to leave a quick example of how to handle the new modular API for anyone migrating to v23.

@mikehardy, feel free to chime in if there's a cleaner way to do this!


Implementing Modular Remote Config (v23.x.x)

With the release of version 23.x.x, React Native Firebase has fully embraced the Modular API (similar to the Firebase Web SDK v9).

What has changed?

In previous versions, we used a class-based instance (e.g., remoteConfig().fetchAndActivate()). In the modular version, we now pass the configuration instance as the first argument to standalone functions like fetchAndActivate(instance).

Service Implementation

The following implementation centralizes Remote Config logic into a reusable service:

import { 
  fetchAndActivate, 
  getRemoteConfig, 
  getValue, 
  setConfigSettings 
} from '@react-native-firebase/remote-config';

// Cache time constant (e.g., 5 minutes)
export const REMOTE_CONFIG_CACHE_TIME = 300000;

let remoteConfig: any = null;

/**
 * Initializes the Remote Config instance and sets global settings.
 */
const initializeRemoteConfig = async () => {
  if (!remoteConfig) {
    remoteConfig = getRemoteConfig();
  }

  await setConfigSettings(remoteConfig, {
    minimumFetchIntervalMillis: REMOTE_CONFIG_CACHE_TIME
  });
};

/**
 * Fetches and activates the latest values before returning them as a string.
 */
const getValueAsString = async (property: string): Promise<string> => {
  await fetchAndActivate(remoteConfig);

  return getValue(remoteConfig, property).asString();
};

/**
 * Fetches and activates the latest values before returning them as a boolean.
 */
const getValueAsBoolean = async (property: string): Promise<boolean> => {
  await fetchAndActivate(remoteConfig);

  return getValue(remoteConfig, property).asBoolean();
};

export const RemoteConfigService = {
  getValueAsBoolean,
  getValueAsString,
  initializeRemoteConfig
};

How to use it

1. Global Initialization

It is recommended to initialize the service early in your app's lifecycle (e.g., in App.tsx or a Redux Store).

import { useEffect } from 'react';
import { RemoteConfigService } from './services/RemoteConfigService';

const App = () => {
    const setupRemoteConfig = async () => {
      try {
        await RemoteConfigService.initializeRemoteConfig();
      } catch (error) {
        console.error("Failed to initialize Remote Config:", error);
      }
    };

  useEffect(() => {
    setupRemoteConfig();
  }, []);

  return <MainNavigator />;
};

2. Consuming Values

Since the methods are async, you can call them whenever you need a specific flag:

const isNewUiEnabled = await RemoteConfigService.getValueAsBoolean('enable_new_interface');

Quick Notes

  • Global Instance: Keep in mind that if you're using Expo or standard React Native and have your google-services.json (or GoogleService-Info.plist) correctly set up, @react-native-firebase is instantiated automatically. You don't need to manually initialize the Firebase app yourself. You just need to ensure that the initializeRemoteConfig function from the snippet above is called before you trigger any other service functions.

  • Safety: Always wrap your initialization in a try/catch block to prevent app crashes due to network issues during the initial fetch.


Other Option

  • Self-Initializing Singleton Pattern:
    Instead of relying on the caller to remember to initialize the service in App.tsx, you can bake the initialization check directly into the getters. This ensures the configuration is ready even if a getter is called before the app's main setup finishes.
    Since the initializeRemoteConfig function checks for an existing instance, calling it multiple times has zero overhead after the first successful execution.
let remoteConfig = null

const initializeRemoteConfig = async () => {
  if (remoteConfig) {
    return
  }

  const instance = getRemoteConfig()

  await setConfigSettings(instance, {
    minimumFetchIntervalMillis: REMOTE_CONFIG_CACHE_TIME
  })

  remoteConfig = instance
}

const getValueAsString = async (property: string): Promise<string> => {
  await initializeRemoteConfig()

  await fetchAndActivate(remoteConfig)

  return getValue(remoteConfig, property).asString()
}

const getValueAsBoolean = async (property: string): Promise<boolean> => {
  await initializeRemoteConfig()

  await fetchAndActivate(remoteConfig)

  return getValue(remoteConfig, property).asBoolean()
}

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions