PageSourceSearch

https://reactnative.dev/assets/js/c06eaf22.11ae927b.js

js reactnative.dev collected 2026-09-24 07:17:56 UTC 18,150 bytes, 2 lines download raw bytes

1"use strict";(self.webpackChunkreact_native_website=self.webpackChunkreact_native_website||[]).push([["15737"],{32379(e,a,t){t.r(a),t.d(a,{metadata:()=>i,default:()=>u,frontMatter:()=>o,contentTitle:()=>l,toc:()=>s,assets:()=>c});var i=JSON.parse('{"id":"the-new-architecture/native-modules-lifecycle","title":"Native Modules Lifecycle","description":"In React Native, Native Modules are singleton. The Native Module infrastructure lazily creates a Native Module 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.","source":"@site/versioned_docs/version-0.79/the-new-architecture/native-modules-lifecycle.md","sourceDirName":"the-new-architecture","slug":"/the-new-architecture/native-modules-lifecycle","permalink":"/docs/0.79/the-new-architecture/native-modules-lifecycle","draft":false,"unlisted":false,"editUrl":"[{\\"label\\":\\"Edit page for next release\\",\\"href\\":\\"https://github.com/facebook/react-native-website/edit/main/docs/the-new-architecture/native-modules-lifecycle.md\\"},{\\"label\\":\\"Edit page for 0.79 release\\",\\"href\\":\\"https://github.com/facebook/react-native-website/edit/main/website/versioned_docs/version-0.79/the-new-architecture/native-modules-lifecycle.md\\"}]","tags":[],"version":"0.79","lastUpdatedAt":1762937229000,"frontMatter":{}}'),n=t(62540),r=t(43023);t(77779),t(98263),t(38469);let o={},l="Native Modules Lifecycle",c={},s=[{value:"Android",id:"android",level:2},{value:"iOS",id:"ios",level:2}];function d(e){let a={a:"a",code:"code",h1:"h1",h2:"h2",header:"header",li:"li",ol:"ol",p:"p",pre:"pre",...(0,r.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(a.header,{children:(0,n.jsx)(a.h1,{id:"native-modules-lifecycle",children:"Native Modules Lifecycle"})}),"\n",(0,n.jsx)(a.p,{children:"In React Native, Native Modules are singleton. The Native Module infrastructure lazily creates a Native Module 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."}),"\n",(0,n.jsxs)(a.p,{children:["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 ",(0,n.jsx)(a.a,{href:"/docs/integration-with-existing-apps",children:"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."]}),"\n",(0,n.jsx)(a.p,{children:"When this happens, Native Modules 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."}),"\n",(0,n.jsxs)(a.p,{children:["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 ",(0,n.jsx)(a.a,{href:"/docs/next/turbo-native-modules-introduction",children:"Native Modules guide"})," first."]}),"\n",(0,n.jsx)(a.h2,{id:"android",children:"Android"}),"\n",(0,n.jsxs)(a.p,{children:["When it comes to Android, all the Native Modules already implements a ",(0,n.jsx)(a.a,{href:"https://github.com/facebook/react-native/blob/main/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/interfaces/TurboModule.kt",children:"TurboModule"})," interface that defines two methods: ",(0,n.jsx)(a.code,{children:"initialize()"})," and ",(0,n.jsx)(a.code,{children:"invalidate()"}),"."]}),"\n",(0,n.jsxs)(a.p,{children:["The ",(0,n.jsx)(a.code,{children:"initialize()"}
1)," 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 ",(0,n.jsx)(a.code,{children:"initialize()"})," method: ",(0,n.jsx)(a.a,{href:"https://github.com/facebook/react-native/blob/0617accecdcb11159ba15c34885f294bc206aa89/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java#L155-L157",children:"BlobModule"}),", ",(0,n.jsx)(a.a,{href:"https://github.com/facebook/react-native/blob/0617accecdcb11159ba15c34885f294bc206aa89/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java#L193-L197",children:"NetworkingModule"}),"."]}),"\n",(0,n.jsxs)(a.p,{children:["The ",(0,n.jsx)(a.code,{children:"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 ",(0,n.jsx)(a.code,{children:"invalidate()"})," method: ",(0,n.jsx)(a.a,{href:"https://github.com/facebook/react-native/blob/0617accecdcb11159ba15c34885f294bc206aa89/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/deviceinfo/DeviceInfoModule.kt#L72-L76",children:"DeviceInfoModule"}),", ",(0,n.jsx)(a.a,{href:"https://github.com/facebook/react-native/blob/0617accecdcb11159ba15c34885f294bc206aa89/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java#L200-L212",children:"NetworkModule"})]}),"\n",(0,n.jsx)(a.h2,{id:"ios",children:"iOS"}),"\n",(0,n.jsxs)(a.p,{children:["On iOS, Native Modules conforms to the ",(0,n.jsx)(a.a,{href:"https://github.com/facebook/react-native/blob/0617accecdcb11159ba15c34885f294bc206aa89/packages/react-native/ReactCommon/react/nativemodule/core/platform/ios/ReactCommon/RCTTurboModule.h#L196-L200",children:(0,n.jsx)(a.code,{children:"RCTTurboModule"})})," protocol. However, this protocol does not expose the ",(0,n.jsx)(a.code,{children:"initialize"})," and ",(0,n.jsx)(a.code,{children:"invalidate"})," method that are exposed by the Android's ",(0,n.jsx)(a.code,{children:"TurboModule"})," class."]}),"\n",(0,n.jsxs)(a.p,{children:["Instead, on iOS, there are two additional protocols: ",(0,n.jsx)(a.a,{href:"https://github.com/facebook/react-native/blob/0617accecdcb11159ba15c34885f294bc206aa89/packages/react-native/React/Base/RCTInitializing.h",children:(0,n.jsx)(a.code,{children:"RCTInitializing"})})," and ",(0,n.jsx)(a.a,{href:"https://github.com/facebook/react-native/blob/0617accecdcb11159ba15c34885f294bc206aa89/packages/react-native/React/Base/RCTInvalidating.h",children:(0,n.jsx)(a.code,{children:"RCTInvalidating"})}),". These protocols are used to define the ",(0,n.jsx)(a.code,{children:"initialize"})," and ",(0,n.jsx)(a.code,{children:"invalidate"})," methods, respectively."]}),"\n",(0,n.jsxs)(a.p,{children:["If your module needs to run some initialization code, then you can conform to the ",(0,n.jsx)(a.code,{children:"RCTInitializing"})," protocol and implement the ",(0,n.jsx)(a.code,{children:"initialize"})," method. To do so, you have to:"]}),"\n",(0,n.jsxs)(a.ol,{children:["\n",(0,n.jsxs)(a.li,{children:["Moduify the ",(0,n.jsx)(a.code,{children:"NativeModule.h"})," file by adding the following lines:"]}),"\n"]}),"\n",(0,n.jsx)(a.pre,{children:(0,n.jsx)(a.code,{className:"language-diff",metastring:'title="NativeModule.h"',children:"+ #import <React/RCTInitializing.h>\n\n//...\n\n- @interface NativeModule : NSObject <NativeModuleSpec>\n+ @interface NativeModule : NSObject <NativeModuleSpec, RCTInitializing>\n//...\n@end\n"})}),"\n",(0,n.jsxs)(a.ol,{start:"2",children:["\n",(0,n.jsxs)(a.li,{children:["Implement the ",(0,n.jsx)(a.code,{children:"initialize"})," method in the ",(0,n.jsx)(a.code,{children:"NativeModule.mm"})," file:"]}),"\n"]}),"\n",(0,n.jsx)(a.pre,{children:(0,n.jsx)(a.code,{className:"language-diff",metastring:'title="NativeModule.mm"',children:"// ...\n\n@implementation NativeModule\n\n+- (void)initialize {\n+ // add the initialization code here\n+}\n\n@end\n"})}),"\n",(0,n.jsxs)(a.p,{children:["These are some Native Modules from core that implements the ",(0,n.jsx)(a.code,{children:"initialize"})," method: ",(0,n.jsx)(a.a,{href:"https://github.com/facebook/react-native/blob/0617accecdcb11159ba15c34885f294bc206aa89/packages/react-native/Libraries/Blob/RCTBlobManager.mm#L58-L68",children:"RCTBlobManager"}),", ",(0,n.jsx)(a.a,{href:"https://github.com/facebook/react-native/blob/0617accecdcb11159ba15c34885f294bc206aa89/packages/react-native/React/CoreModules/RCTTiming.mm#L121-L124",children:"RCTTiming"}),"."]}),"\n",(0,n.jsxs)(a.p,{children:["If your module needs to run some cleanup code, then you can conform to the ",(0,n.jsx)(a.code,{children:"RCTInvalidating"})," protocol and implement the ",(0,n.jsx)(a.code,{children:"invalidate"})," method. To do so, you have to:"]}),"\n",(0,n.jsxs)(a.ol,{children:["\n",(0,n.jsxs)(a.li,{children:["Moduify the ",(0,n.jsx)(a.code,{children:"NativeModule.h"})," file by adding the following lines:"]}),"\n"]}),"\n",(0,n.jsx)(a.pre,{children:(0,n.jsx)(a.code,{className:"language-diff",metastring:'title="NativeModule.h"',children:"+ #import <React/RCTInvalidating.h>\n\n//...\n\n- @interface NativeModule : NSObject <NativeModuleSpec>\n+ @interface NativeModule : NSObject <NativeModuleSpec, RCTInvalidating>\n\n//...\n\n@end\n"})}),"\n",(0,n.jsxs)(a.ol,{start:"2",children:["\n",(0,n.jsxs)(a.li,{children:["Implement the ",(0,n.jsx)(a.code,{children:"invalidate"})," method in the ",(0,n.jsx)(a.code,{children:"NativeModule.mm"})," file:"]}),"\n"]}),"\n",(0,n.jsx)(a.pre,{children:(0,n.jsx)(a.code,{className:"language-diff",metastring:'title="NativeModule.mm"',children:"\n// ...\n\n@implementation NativeModule\n\n+- (void)invalidate {\n+ // add the cleanup code here\n+}\n\n@end\n"})}),"\n",(0,n.jsxs)(a.p,{children:["These are some Native Modules from core that implements the ",(0,n.jsx)(a.code,{children:"invalidate"})," method: ",(0,n.jsx)(a.a,{href:"https://github.com/facebook/react-native/blob/0617accecdcb11159ba15c34885f294bc206aa89/packages/react-native/React/CoreModules/RCTAppearance.mm#L151-L155",children:"RCTAppearance"}),", ",(0,n.jsx)(a.a,{href:"https://github.com/facebook/react-native/blob/0617accecdcb11159ba15c34885f294bc206aa89/packages/react-native/React/CoreModules/RCTDeviceInfo.mm#L127-L133",children:"RCTDeviceInfo"}),"."]})]})}function u(e={}){let{wrapper:a}={...(0,r.R)(),...e.components};return a?(0,n.jsx)(a,{...e,children:(0,n.jsx)(d,{...e})}):d(e)}},98263(e,a,t){t.d(a,{A:()=>l});var i=t(62540);t(63696);var n=t(11750),r=t(23865);function o({children:e,className:a,hidden:t}){return(0,i.jsx)("div",{role:"tabpanel",className:(0,n.A)("tabItem_wHwb",a),hidden:t,children:e})}function l({children:e,className:a,value:t}){let{selectedValue:n,lazy:c}=(0,r.uc)(),s=t===n;return!s&&c?null:(0,i.jsx)(o,{className:a,hidden:!s,children:e})}},77779(e,a,t){t.d(a,{A:()=>h});var i=t(62540);t(63696);var n=t(11750),r=t(46065),o=t(23865),l=t(45194),c=t(83029);function s({className:e}){let{selectedValue:a,selectValue:t,tabValues:r,block:c}=(0,o.uc)(),d=[],{blockElementScrollPositionUntilNextRender:u}
1=(0,l.a_)(),h=e=>{let i=e.currentTarget,n=r[d.indexOf(i)].value;n!==a&&(u(i),t(n))},v=e=>{let a=null;switch(e.key){case"Enter":h(e);break;case"ArrowRight":{let t=d.indexOf(e.currentTarget)+1;a=d[t]??d[0];break}case"ArrowLeft":{let t=d.indexOf(e.currentTarget)-1;a=d[t]??d[d.length-1]}}a?.focus()};return(0,i.jsx)("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,n.A)("tabs",{"tabs--block":c},e),children:r.map(({value:e,label:t,attributes:r})=>(0,i.jsx)("li",{role:"tab",tabIndex:a===e?0:-1,"aria-selected":a===e,ref:e=>{d.push(e)},onKeyDown:v,onClick:h,...r,className:(0,n.A)("tabs__item","tabItem_l0OV",r?.className,{"tabs__item--active":a===e}),children:t??e},e))})}function d({children:e}){return(0,i.jsx)("div",{className:"margin-top--md",children:e})}function u({className:e,children:a}){return(0,i.jsxs)("div",{className:(0,n.A)(r.G.tabs.container,"tabs-container","tabList_J5MA"),children:[(0,i.jsx)(s,{className:e}),(0,i.jsx)(d,{children:a})]})}function h(e){let a=(0,c.A)(),t=(0,o.OC)(e);return(0,i.jsx)(o.O_,{value:t,children:(0,i.jsx)(u,{className:e.className,children:(0,o.vT)(e.children)})},String(a))}},23865(e,a,t){t.d(a,{OC:()=>h,O_:()=>m,uc:()=>p,vT:()=>d});var i=t(62540),n=t(63696),r=t(49519),o=t(6743),l=t(88511),c=t(15396),s=t(89030);function d(e){return n.Children.toArray(e).filter(e=>"\n"!==e)}function u({value:e,tabValues:a}){return a.some(a=>a.value===e)}function h(e){let a,{defaultValue:t,queryString:i=!1,groupId:d}=e,h=function(e){let{values:a,children:t}=e;return(0,n.useMemo)(()=>{let e=a??n.Children.toArray(t).flatMap(e=>{if(!e)return[];if((0,n.isValidElement)(e)&&function(e){let{props:a}=e;return!!a&&"object"==typeof a&&"value"in a}(e))return[e];let a="string"==typeof e.type?e.type:e.type.name;throw Error(`Docusaurus error: Bad <Tabs> child <${a}>: all children of the <Tabs> component should be <TabItem>, and every <TabItem> should have a unique "value" prop.
2If you do not want to pass on a "value" prop to the direct children of <Tabs>, you can also pass an explicit <Tabs values={...}> prop.`)}).map(({props:{value:e,label:a,attributes:t,default:i}})=>({value:e,label:a,attributes:t,default:i})),i=(0,c.XI)(e,(e,a)=>e.value===a.value);if(i.length>0)throw Error(`Docusaurus error: Duplicate values "${i.map(e=>`'${e.value}'`).join(", ")}" found in <Tabs>. Every value needs to be unique.`);return e},[a,t])}(e),[v,p]=(0,n.useState)(()=>(function({defaultValue:e,tabValues:a}){if(0===a.length)throw Error("Docusaurus error: the <Tabs> component requires at least one <TabItem> children component");if(e){if(!u({value:e,tabValues:a}))throw Error(`Docusaurus error: The <Tabs> has a defaultValue "${e}" but none of its children has the corresponding value. Available values are: ${a.map(e=>e.value).join(", ")}. If you intend to show no default tab, use defaultValue={null} instead.`);return e}let t=a.find(e=>e.default)??a[0];if(!t)throw Error("Unexpected error: 0 tabValues");return t.value})({defaultValue:t,tabValues:h})),[m,f]=function({queryString:e=!1,groupId:a}){let t=(0,r.W6)(),i=function({queryString:e=!1,groupId:a}){if("string"==typeof e)return e;if(!1===e)return null;if(!0===e&&!a)throw Error('Docusaurus error: The <Tabs> component groupId prop is required if queryString=true, because this value is used as the search param name. You can also provide an explicit value such as queryString="my-search-param".');return a??null}({queryString:e,groupId:a});return[(0,l.aZ)(i),(0,n.useCallback)(e=>{if(!i)return;let a=new URLSearchParams(t.location.search);a.set(i,e),t.replace({...t.location,search:a.toString()})},[i,t])]}({queryString:i,groupId:d}),[b,g]=function({groupId:e}){let a=e?`docusaurus.tab.${e}`:null,[t,i]=(0,s.Dv)(a);return[t,(0,n.useCallback)(e=>{a&&i.set(e)},[a,i])]}({groupId:d}),x=u({value:a=m??b,tabValues:h})?a:null;return(0,o.A)(()=>{x&&p(x)},[x]),{selectedValue:v,selectValue:(0,n.useCallback)(e=>{if(!u({value:e,tabValues:h}))throw Error(`Can't select invalid tab value=${e}`);p(e),f(e),g(e)},[f,g,h]),tabValues:h,lazy:e.lazy??!1,block:e.block??!1}}let v=(0,n.createContext)(null);function p(){let e=n.useContext(v);if(!e)throw Error("useTabsContext() must be used within a Tabs component");return e}function m(e){return(0,i.jsx)(v.Provider,{value:e.value,children:e.children})}},38469(e,a,t){t.d(a,{A:()=>o});var i=t(93227);let n=!!i.A.canUseDOM&&navigator.platform.startsWith("Mac"),r=!!i.A.canUseDOM&&navigator.platform.startsWith("Win"),o={defaultGuide:"quickstart",defaultJsDebugger:"flipper",defaultOs:n?"macos":r?"windows":"linux",defaultPackageManager:"npm",defaultPlatform:n?"ios":"android",defaultSyntax:"functional",defaultAndroidLanguage:"java",defaultAppleLanguage:"objc",defaultJavaScriptSpecLanguages:"typescript",getDevNotesTabs:(e=["android","ios","web","windows"])=>[e.includes("android")?{label:"Android",value:"android"}:void 0,e.includes("ios")?{label:"iOS",value:"ios"}:void 0,e.includes("web")?{label:"Web",value:"web"}:void 0,e.includes("windows")?{label:"Windows",value:"windows"}
2:void 0].filter(Boolean),guides:[{label:"Expo Go Quickstart",value:"quickstart"},{label:"React Native CLI Quickstart",value:"native"}],oses:[{label:"macOS",value:"macos"},{label:"Windows",value:"windows"},{label:"Linux",value:"linux"}],packageManagers:[{label:"npm",value:"npm"},{label:"Yarn",value:"yarn"}],platforms:[{label:"Android",value:"android"},{label:"iOS",value:"ios"}],syntax:[{label:"Function Component",value:"functional"},{label:"Class Component",value:"classical"}],androidLanguages:[{label:"Java",value:"java"},{label:"Kotlin",value:"kotlin"}],appleLanguages:[{label:"ObjectiveC",value:"objc"},{label:"Swift",value:"swift"}],javaScriptSpecLanguages:[{label:"TypeScript",value:"typescript"},{label:"Flow",value:"flow"}],jsDebuggers:[{label:"Hermes Debugger / Expo",value:"hermes"},{label:"Flipper",value:"flipper"},{label:"New Debugger (Experimental)",value:"new-debugger"}],snackLanguages:[{label:"TypeScript",value:"typescript"},{label:"JavaScript",value:"javascript"}],defaultSnackLanguage:"typescript"}},43023(e,a,t){t.d(a,{R:()=>o,x:()=>l});var i=t(63696);let n={},r=i.createContext(n);function o(e){let a=i.useContext(r);return i.useMemo(function(){return"function"==typeof e?e(a):{...a,...e}},[a,e])}function l(e){let a;return a=e.disableParentContext?"function"==typeof e.components?e.components(n):e.components||n:o(e.components),i.createElement(r.Provider,{value:a},e.children)}}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.