Native Modules Lifecycle
In React Native, Native Modules are singleton. The Native Module infrastructure lazily creates a Native Modules the first time it is accessed and it keeps it around whenever the app requires it. This is a performance optimization that allows us to avoid the overhead of creating Native Modules eagerly, at app start, and it ensure faster startup times.
In a pure React Native app, the Native Modules are created once and they are never destroyed. However, in more complex apps, there might be use cases where the Native Modules are destroyed and recreated. Imagine, for example, a brownfield app that mixes some native views with some React Native surfaces, as presented in the Integrating with Existing App guide. In that case it might make sense to destroy a React Native instance when the user navigates away from a React Native surface and recreate it when the user navigates back to that surface.
When this happens, Native Module that are stateless won't cause any issues. However, for stateful Native Modules it might be necessary to properly invalidate the Native Module to ensure that the state is reset and the resources released.
In this guide, you will explore how to initialize and invalidate a Native Module properly. This guide assumes that you are familiar with how to write a Native Modules and you are comfortable writing native code. If you are not familiar with Native Modules, please read the Native Modules guide first.
Android
When it comes to Android, all the Native Modules already implements a TurboModule interface that defines two methods: initialize()
and invalidate()
.
The initialize()
method is called by the Native Module infrastructure when the Native Module is created. This is the best place to put all the initialization code that needs access to the ReactApplicationContext, for example. These are some Native Modules from core that implements the initialize()
method: BlobModule, NetworkingModule.
The invalidate()
method is called by the Native Module infrastructure when the Native Module is destroyed. This is the best place to put all the cleanup code, resetting the Native Module state and release resources that are no longer needed, such as memory and files. These are some Native Modules from core that implements the invalidate()
method: DeviceInfoModule, NetworkModule
iOS
On iOS, Native Modules conforms to the RCTTurboModule
protocol. However, this protocol does not expose the initialize
and invalidate
method that are exposed by the Android's TurboModule
class.
Instead, on iOS, there are two additional protocols: RCTInitializing
and RCTInvalidating
. These protocols are used to define the initialize
and invalidate
methods, respectively.
If your module needs to run some initialization code, then you can conform to the RCTInitializing
protocol and implement the initialize
method. To do so, you have to:
- Moduify the
NativeModule.h
file by adding the following lines:
+ #import <React/RCTInitializing.h>
//...
- @interface NativeModule : NSObject <NativeModuleSpec>
+ @interface NativeModule : NSObject <NativeModuleSpec, RCTInitializing>
//...
@end
- Implement the
initialize
method in theNativeModule.mm
file:
// ...
@implementation NativeModule
+- (void)initialize {
+ // add the initialization code here
+}
@end
These are some Native Modules from core that implements the initialize
method: RCTBlobManager, RCTTiming.
If your module needs to run some cleanup code, then you can conform to the RCTInvalidating
protocol and implement the invalidate
method. To do so, you have to:
- Moduify the
NativeModule.h
file by adding the following lines:
+ #import <React/RCTInvalidating.h>
//...
- @interface NativeModule : NSObject <NativeModuleSpec>
+ @interface NativeModule : NSObject <NativeModuleSpec, RCTInvalidating>
//...
@end
- Implement the
invalidate
method in theNativeModule.mm
file:
// ...
@implementation NativeModule
+- (void)invalidate {
+ // add the cleanup code here
+}
@end
These are some Native Modules from core that implements the invalidate
method: RCTAppearance, RCTDeviceInfo.