From 7c1091c6e37f60fc9d83d2da67cdb80a5934ba92 Mon Sep 17 00:00:00 2001 From: Arati Chilad <58401542+arati-1@users.noreply.github.com> Date: Thu, 8 Sep 2022 09:19:13 -0700 Subject: [PATCH] The New Architecture section editorial review (#3288) * [Do Not Merge] Refactoring The New Architecture (#3029) * [Guide - The New Architecture] What Backward Compatibility Is (#3038) * Guide to creating a New Architecture app from template (#3056) * Start new template guide This is a first iteration. I want to get feedback on a few aspects, so starting from here as a baseline. * Update title * Use tabs for target OS Set up matching the style of "Getting Started", except I kept the headers inside the tabs for now as it makes for a useful right-hand TOC. * Capitalize New Architecture, simplify * Preliminary section for Hermes Add section for recommending enabling Hermes. Not sure of contents yet, and still have to test. * Reword to emphasize importance of Hermes usage * Show new arch in use * Add build speed article link * Add pro tip for pod install alias * Restructure, repeat less Favor linking to original setup guide instead of repeating content. * Note about Expo * Include command on uninstalling global CLI * How to learn more * Remove headers in tabs They don't work correctly with the righthand TOC. * Make header more clear * Use quote block less often There was way too much yellow. * Opt for instructions using XCode Because `xcodebuild clean` already failed me once when XCode GUI clean worked. * Fix lint issue * Improve wording * Use product name * Fix line wraps * Reword based on feedback * Note use of bundle install * Pod removal instructions Also standardize on using yarn scripts from template for commands, it's a little confusing to see the mix of `npx` and `yarn` once we start referring to `yarn pod-install` * Convert quotes to admonitions * Convert Note: to admonitions * Feedback: Change admonitions to caution * PR feedback * New Architecture landing page (#3072) * First draft of landing page * Add migration and backwards compatibility links * lint fix * Restructure slightly, leaning more on context from Why a New Architecture * Don't need md in links * Suggested rewording * Rephrase pillar summaries * [Guide - The New Architecture] Why A New Architecture (#3043) * [Guide - The New Architecture] Pillars (#3046) * [Guide - The New Architecture] TurboModules as Native Modules (#3039) * [Guide - The New Architecture] Fabric Components as Native Components (#3040) * [FEAT][TNA] Fabric Component Guide (#3132) * [Feat] Add intro for Fabric Components * feat: add guide to create a Fabric Component * Add page on codegen (#3155) * [FEAT] TurboModules guide (#3168) * [Feat] Add intro for Fabric Components * feat: add guide to create a Fabric Component * Beginning of guide/folder structure * WIP JS Spec * specification section * Configuration * native code intro * Must be named Spec * Best stab at iOS native code, but I don't know how to describe what's going on in the code very well. Extrapolated what I could. * Android instructions iOS isn't working for me. Builds, but can't load module. Writing up Android auto-linking next because the steps I tested did work. * Include linking instructions from RNNArch repo * Add example JavaScript * native modules link * Address quick feedback items * Remove, fix for rebased branch * fix TM parameter on Android * Revert to 'Codegen' casing * Revert folly version change 2021.07.22 is for current version on main * fix typo * getTurboModule explainer * Sentence edits - Fix acronym bolding - Change wording to "recommended" because "standard" has other connotations of possibly being required - Parentheses unnecessary, distracting * Remove TODO for now Getting inconsistent results here, not sure if this is wrong or not; removing TODO for now so it doesn't block anything * ABI rephrase, more in line with new Fabric guide wording * Explain shared C++ code more * feat: add guide to create a Fabric Component * feat: add guide to create a Fabric Component * package.json description * Lint fixes * fix: Move JS constants to reduce changes * fix: Remove newline * feat: add required step for Android Codegen * fix: use the proper links Co-authored-by: Riccardo Cipolleschi * wip: migration guide review (#3200) * Fix for some typos and other editorial related changes * Update docs/the-new-architecture/pillars-fabric-components.md correcting the article Co-authored-by: Riccardo * Update pillars-fabric-components.md Co-authored-by: Riccardo Co-authored-by: Lizzi Lindboe Co-authored-by: Riccardo --- docs/new-architecture-app-intro.md | 20 ++++---- docs/new-architecture-library-android.md | 14 +++--- docs/new-architecture-library-intro.md | 48 +++++++++---------- docs/new-architecture-library-ios.md | 12 ++--- ...ackward-compatibility-fabric-components.md | 22 ++++----- .../backward-compatibility-turbomodules.md | 24 +++++----- docs/the-new-architecture/landing-page.md | 12 ++--- docs/the-new-architecture/pillars-codegen.md | 42 ++++++++-------- .../pillars-fabric-components.md | 34 ++++++------- .../pillars-turbomodule.md | 30 ++++++------ docs/the-new-architecture/pillars.md | 8 ++-- docs/the-new-architecture/use-app-template.md | 20 ++++---- docs/the-new-architecture/why.md | 30 ++++++------ 13 files changed, 158 insertions(+), 158 deletions(-) diff --git a/docs/new-architecture-app-intro.md b/docs/new-architecture-app-intro.md index dc7948d4dff..2b872ced579 100644 --- a/docs/new-architecture-app-intro.md +++ b/docs/new-architecture-app-intro.md @@ -9,11 +9,11 @@ import NewArchitectureWarning from './\_markdown-new-architecture-warning.mdx'; There are a few prerequisites that should be addressed before the New Architecture is enabled in your application. -## Use a React Native >= 0.68 release +## Use a React Native >= 0.68 Release React Native released the support for the New Architecture with the release `0.68.0`. -This guide is written with the expectation that you’re using the latest React Native release. At the moment of writing, this is `0.70.0`. Other than this guide, you can leverage the [upgrade helper](https://react-native-community.github.io/upgrade-helper/) to determine what other changes may be required for your project. +This guide is written with the expectation that you’re using the latest React Native release. At the moment of writing, this is `0.70.0`. Besides this guide, you can leverage the [upgrade helper](https://react-native-community.github.io/upgrade-helper/) to determine what other changes may be required for your project. To update to the most recent version of React Native, you can run this command: @@ -27,7 +27,7 @@ Starting from React Native `0.69.0`, you may also need to update the version of yarn add react@18.0.0 ``` -### Android specifics +### Android Specifics Using the New Architecture on Android has some prerequisites that you need to meet: @@ -139,9 +139,9 @@ task copyDownloadableDepsToLibs(type: Copy) { + } ``` -Finally, it’s time to update your project to use the `react-native` dependency from source, rather than using a precompiled artifact from the NPM package. This is needed as the later setup will rely on building the native code from source. +Finally, it’s time to update your project to use the `react-native` dependency from the source rather than using a precompiled artifact from the NPM package. This is needed as the later setup will rely on building the native code from the source. -Let’s edit your **module-level** `build.gradle` (the one inside `app/` folder) and change the following line: +Let’s edit your **module-level** `build.gradle` (the one inside the `app/` folder) and change the following line: ```diff dependencies { @@ -151,7 +151,7 @@ dependencies { ## Use Hermes -Hermes is an open-source JavaScript engine optimized for React Native. Hermes is enabled by default and you have to explicitly disable it if you want to use JSC. +Hermes is an open-source JavaScript engine optimized for React Native. Hermes is enabled by default, and you have to explicitly disable it if you want to use JSC. We highly recommend using Hermes in your application. With Hermes enabled, you will be able to use the JavaScript debugger in Flipper to directly debug your JavaScript code. @@ -159,7 +159,7 @@ Please [follow the instructions on the React Native website](hermes) to learn ho :::caution -**iOS:** If you opt out of using Hermes, you will need to replace `HermesExecutorFactory` with `JSCExecutorFactory` in any examples used throughout the rest of this guide. +**iOS:** If you opt-out of using Hermes, you will need to replace `HermesExecutorFactory` with `JSCExecutorFactory` in any examples used throughout the rest of this guide. ::: @@ -201,7 +201,7 @@ cd android ./gradlew clean ``` -## iOS: Make the project build +## iOS: Build the Project After upgrading the project, there are a few changes you need to apply: @@ -228,7 +228,7 @@ echo 'export NODE_BINARY=$(command -v node)' > .xcode.env ``` If you need it, you can also open the file and replace the `$(command -v node)` with the path to the node executable. -React Native supports also a local version of this file `.xcode.env.local`. This file is not synced with the repository to let you customize your local setup, if it differs from the Continuous Integration or the team one. +React Native also supports a local version of this file `.xcode.env.local`. This file is not synced with the repository to let you customize your local setup, if it differs from the Continuous Integration or the team one. ## iOS: Use Objective-C++ (`.mm` extension) @@ -261,7 +261,7 @@ Then, declare your app delegate as a `RCTCxxBridgeDelegate` provider: @end ``` -To conform to the `RCTCxxBridgeDelegate` protocol, you will need to implement the `jsExecutorFactoryForBridge:` method. Typically, this is where you would return a `JSCExecutorFactory` or `HermesExecutorFactory`, and we will use it to install our TurboModules bindings later on. +To conform to the `RCTCxxBridgeDelegate` protocol, you must implement the `jsExecutorFactoryForBridge:` method. Typically, this is where you would return a `JSCExecutorFactory` or `HermesExecutorFactory`, and we will use it to install our TurboModules bindings later on. You can implement the `jsExecutorFactoryForBridge:` method like this: diff --git a/docs/new-architecture-library-android.md b/docs/new-architecture-library-android.md index 09f1ee2fb7f..f0f702941fb 100644 --- a/docs/new-architecture-library-android.md +++ b/docs/new-architecture-library-android.md @@ -7,11 +7,11 @@ import NewArchitectureWarning from './\_markdown-new-architecture-warning.mdx'; -Once you have defined the JavaScript specs for your native modules as part of the [prerequisites](new-architecture-library-intro), setup the configuration of the Codegen, and followed the Android/Gradle setup, you are now ready to migrate your library to the new architecture. Here are the steps you can follow to accomplish this. +Once you have defined the JavaScript specs for your native modules as part of the [prerequisites](new-architecture-library-intro), set up the configuration of the Codegen, and follow the Android/Gradle setup, you are now ready to migrate your library to the new architecture. Here are the steps you can follow to accomplish this. -## 1. Extend or implement the code-generated native interfaces +## 1. Extend or Implement the Code-generated Native Interfaces -The JavaScript spec for your native module or component will be used to generate native interface code for each supported platform (i.e. Android and iOS). These native interface files will be generated **when a React Native application that depends on your library is built**. +The JavaScript spec for your native module or component will be used to generate native interface code for each supported platform (i.e., Android and iOS). These native interface files will be generated **when a React Native application that depends on your library is built**. While this generated native interface code **will not ship as part of your library**, you do need to make sure your Java/Kotlin code conforms to the protocols provided by these native interface files. @@ -23,7 +23,7 @@ You can invoke the `generateCodegenArtifactsFromSchema` Gradle task to generate The files that are output can be found inside `build/generated/source/codegen` and **should not be committed**, but you’ll need to refer to them to determine what changes you need to make to your native modules in order for them to provide an implementation for each generated interface. -The output of the codegen for a module called `NativeAwesomeManager` will look like this: +The output of the Codegen for a module called `NativeAwesomeManager` will look like this: ``` app/build/generated/source/codegen @@ -51,9 +51,9 @@ app/build/generated/source/codegen └── schema.json ``` -### Extends the abstract class provided by the codegen +### Extends the Abstract Class Provided by the Codegen -Update your native module or component to ensure it **extends the abstract class** that has been code-generated from your JavaScript specs (i.e. the `NativeAwesomeManagerSpec.java` file from the previous example). +Update your native module or component to ensure it **extends the abstract class** that has been code-generated from your JavaScript specs (i.e., the `NativeAwesomeManagerSpec.java` file from the previous example). Following the example set forth in the previous section, your library might import `NativeAwesomeManagerSpec`, implement the relevant native interface and the necessary methods for it: @@ -115,4 +115,4 @@ class NativeAwesomeManager(reactContext: ReactApplicationContext) : -Please note that the **generated abstract class** that you’re now extending (`MyAwesomeSpec` in this example), is itself extending `ReactContextBaseJavaModule`. Therefore you should not use access to any of the method/fields you were previously using (e.g. the `ReactApplicationContext` and so on). Moreover the generated class will now also implement the `TurboModule` interface for you. +Please note that the **generated abstract class** that you’re now extending (`MyAwesomeSpec` in this example) is itself extending `ReactContextBaseJavaModule`. Therefore you should not use access to any of the method/fields you were previously using (e.g., the `ReactApplicationContext` and so on). Moreover, the generated class will now also implement the `TurboModule` interface for you. diff --git a/docs/new-architecture-library-intro.md b/docs/new-architecture-library-intro.md index 403ce6f6343..9d688a8151e 100644 --- a/docs/new-architecture-library-intro.md +++ b/docs/new-architecture-library-intro.md @@ -14,14 +14,14 @@ The following steps will help ensure your modules and components are ready for t ## Define Specs in JavaScript -The JavaScript specs serve as the source of truth for the methods that are provided by each native module. They defines all APIs that are provided by the native module, along with the types of those constants and functions. -Using a **typed** spec file allows to be intentional and declare all the input arguments and outputs of your native module’s methods. +The JavaScript specs serve as the source of truth for the methods that are provided by each native module. They define all APIs that are provided by the native module, along with the types of those constants and functions. +Using a **typed** spec file allows you to be intentional and declare all the input arguments and outputs of your native module’s methods. :::info -Currently, this guide is written under the assumption that you will be using [Flow](https://flow.org/). The `react-native-codegen` package is also currently working only with Flow source as input. **TypeScript** support is in beta right now. +Currently, this guide is written under the assumption that you will be using [Flow](https://flow.org/). The `react-native-codegen` package is also currently working only with the Flow source as an input. **TypeScript** support is in beta right now. ::: -To adopt the New Architecture, you start by creating these specs for your native modules and native components. You can do this prior to actually migrating to the New Architecture: the specs will be used later on to generate native interface code for all the supported platforms, as a way to enforce uniform APIs across platforms. +To adopt the New Architecture, you start by creating these specs for your native modules and native components. You can do this prior to actually migrating to the New Architecture: the specs will be used later on to generate native interface code for all the supported platforms as a way to enforce uniform APIs across platforms. #### Turbomodules @@ -124,12 +124,12 @@ When using Flow or TypeScript, you will be using [type annotations](https://flow -In general, this means you can use primitive types (strings, numbers, booleans), as well as function types, object types, and array types. Union types, on the other hand, are not supported. All types must be read-only. For Flow: either `+` or `$ReadOnly<>` or `{||}` objects. For TypeScript: `readonly` for properties, `Readonly<>` for objects, and `ReadonlyArray<>` for arrays. +In general, this means you can use primitive types (strings, numbers, booleans), and function types, object types, and array types. Union types, on the other hand, are not supported. All types must be read-only. For Flow: either `+` or `$ReadOnly<>` or `{||}` objects. For TypeScript: `readonly` for properties, `Readonly<>` for objects, and `ReadonlyArray<>` for arrays. > See Appendix [I. Flow Type to Native Type Mapping](#i-flow-type-to-native-type-mapping). > See Appendix [II. TypeScript to Native Type Mapping](#ii-typescript-to-native-type-mapping). -### Codegen helper types +### Codegen Helper Types You can use predefined types for your JavaScript spec, here is a list of them: @@ -144,11 +144,11 @@ Later on those types are compiled to coresponding equivalents on target platform ### Be Consistent Across Platforms and Eliminate Type Ambiguity -Before adopting the New Architecture in your native module, you will need to ensure your methods are consistent across platforms. This is something you will realize as you set out to write the JavaScript spec for your native module - remember, that JavaScript spec defines what the methods will look like on all supported platforms. +Before adopting the New Architecture in your native module, you will need to ensure your methods are consistent across platforms. This is something you will realize as you set out to write the JavaScript spec for your native module - remember that JavaScript spec defines what the methods will look like on all supported platforms. -If your existing native module has methods with the same name on multiple platforms, but with different numbers or types of arguments across platforms, you will need to find a way to make these consistent. If you have methods that can take two or more different types for the same argument, you will also need to find a way to resolve this type ambiguity as type unions are intentionally not supported. +If your existing native module has methods with the same name on multiple platforms but with different numbers or types of arguments across platforms, you will need to find a way to make these consistent. If you have methods that can take two or more different types for the same argument, you will also need to find a way to resolve this type of ambiguity as type unions are intentionally not supported. -## Make sure _autolinking_ is enabled +## Make Sure _autolinking_ is Enabled @@ -195,7 +195,7 @@ To determine if your library is set up for autolinking, check the CocoaPods outp ## Configure Codegen -[Codegen](the-new-architecture/pillars-codegen) is a tool that runs when you build an Android app or when you install the dependencies of an iOS app. It creates some scaffolding code that you won't have to create manually. +[Codegen](the-new-architecture/pillars-codegen) is a tool that runs when you build an Android app or install the dependencies of an iOS app. It creates some scaffolding code that you won't have to create manually. Codegen can be configured in the `package.json` file of your Library. Add the following JSON object at the end of it. @@ -213,16 +213,16 @@ Codegen can be configured in the `package.json` file of your Library. Add the fo ``` - The `codegenConfig` is the key used by the Codegen to verify that there is some code to generate. -- The `name` field, is the name of the library. -- The `type` field is used to identify the type of module we want to create. Our suggestions is to keep `all` to support libraries that contains both TurboModule and Fabric Components. +- The `name` field is the name of the library. +- The `type` field is used to identify the type of module we want to create. Our suggestion is to keep `all` to support libraries that contain both TurboModule and Fabric Components. - The `jsSrcsDir` is the directory where the codegen will start looking for JavaScript specs. - The `android.javaPackageName` is the name of the package where the generated code wil end up. Android also requires to have the [React Gradle Plugin properly configured](new-architecture-app-intro#android-specifics) in your app. -## Preparing your JavaScript codebase for the new React Native Renderer (Fabric) +## Preparing your JavaScript Codebase for the new React Native Renderer (Fabric) -The new renderer also known as Fabric doesn’t use the UIManager so direct calls to UIManager will need to be migrated. Historically, calls to UIManager had some pretty complicated patterns. Fortunately, we’ve created new APIs that are much cleaner. These new APIs are forwards compatible with Fabric so you can migrate your code today and they will work properly when you turn on Fabric! +The new renderer, also known as Fabric, doesn’t use the UIManager, so direct calls to UIManager will need to be migrated. Historically, calls to UIManager had some pretty complicated patterns. Fortunately, we’ve created new APIs that are much cleaner. These new APIs are forward compatible with Fabric, so you can migrate your code today, and the APIs will work properly when you turn on Fabric! Fabric will be providing new type safe JS APIs that are much more ergonomic than some of the patterns we've seen in product code today. These APIs require references to the underlying component, no longer using the result of `findNodeHandle`. `findNodeHandle` is used to search the tree for a native component given a class instance. This was breaking the React abstraction model. `findNodeHandle` is not compatible with React 18. Deprecation of `findNodeHandle` in React Native is similar to the [deprecation of `findDOMNode` in React DOM](https://reactjs.org/docs/strict-mode.html#warning-about-deprecated-finddomnode-usage). @@ -275,7 +275,7 @@ class ChildComponent extends React.Component { We can’t convert this call to `this._ref.measure` because `this._ref` is an instance to `ChildComponent`, which is not a HostComponent and thus does not have a `measure` function. -`ChildComponent` renders a `View`, which is a HostComponent, so we need to get a reference to `View` instead. There are typically two approaches to get what we need. If the component we need to get the ref from is a function component using `forwardRef` is probably the right choice. If it is a class component with other public methods, adding a public method for getting the ref is an option. Here are examples of those two forms: +`ChildComponent` renders a `View`, which is a HostComponent, so we need to get a reference to `View` instead. There are typically two approaches to get what we need. If the component we need to get the ref from is a function component, using `forwardRef` is probably the right choice. If it is a class component with other public methods, adding a public method for getting the ref is an option. Here are examples of those two forms: #### Using `forwardRef` @@ -412,11 +412,11 @@ const styles = StyleSheet.create({ }); ``` -In this example when the View is pressed there is a `setNativeProps` call to update the style and accessibility props of the component. To migrate this component it’s important to understand its current behavior using `setNativeProps`. +In this example, when the View is pressed, there is a `setNativeProps` call to update the style and accessibility props of the component. To migrate this component, it’s important to understand its current behavior using `setNativeProps`. #### Pre-Fabric, Component Props Persist -On first render, the component props are those declared in the render function. After the View is pressed `_onSubmit` calls `setNativeProps` with updated prop values. +On the first render, the component props are those declared in the render function. After the View is pressed `_onSubmit` calls `setNativeProps` with updated prop values. The resulting component can be represented as such: ```jsx @@ -471,10 +471,10 @@ const styles = StyleSheet.create({ }); ``` -- We are using the `hasSubmitted` flag to represent whether or not we want to apply `styles.submittedView`. If the style was dynamic then it makes sense to store the style object in state -- `accessibility` is now explicitly passed to the View component as a boolean. This differs from the prior implementation where `accessibility` wasn’t passed as a prop in initial render but in this case we know the non-specification of `accessibility` is handled in the same way as `accessibilty={false}` +- We are using the `hasSubmitted` flag to represent whether or not we want to apply `styles.submittedView`. If the style was dynamic, then it makes sense to store the style object in state +- `accessibility` is now explicitly passed to the View component as a boolean. This differs from the prior implementation where `accessibility` wasn’t passed as a prop in the initial render, but in this case, we know the non-specification of `accessibility` is handled in the same way as `accessibilty={false}` -Be wary of your assumptions as uncaught subtleties can introduce differences in behavior! It’s a good idea to have snapshot tests of your component as they will highlight any differences pre and post your migration. +Be wary of your assumptions, as uncaught subtleties can introduce differences in behavior! It’s a good idea to have snapshot tests of your component as they will highlight any differences pre and post your migration. ### Move the call to `requireNativeComponent` to a separate file @@ -540,7 +540,7 @@ export default require('./RNTMyNativeViewNativeComponent') ### Migrating off `dispatchViewManagerCommand` -Similar to one above, in an effort to avoid calling methods on the UIManager, all view manager methods are now called through an instance of `NativeCommands`. `codegenNativeCommands` is a new API to code-generate `NativeCommands` given an interface of your view manager’s commands. +Similar to the one above, in an effort to avoid calling methods on the UIManager, all view manager methods are now called through an instance of `NativeCommands`. `codegenNativeCommands` is a new API to code-generate `NativeCommands` given an interface of your view manager’s commands. **Before** @@ -586,7 +586,7 @@ Note: - The first argument in the `moveToRegion` command is a HostComponent ref of the native component - The arguments to the `moveToRegion` command are enumerated in the signature - The command definition is co-located with the native component. This is an encouraged pattern -- Ensure you have included your command name in `supportedCommands` array +- Ensure you have included your command name in the `supportedCommands` array #### Using Your Command @@ -614,9 +614,9 @@ class MyComponent extends React.Component { } ``` -#### Updating Native implementation +#### Updating Native Implementation -In the example the code-generated `Commands` will dispatch `moveToRegion` call to the native component’s view manager. In addition to writing the JS interface, you’ll need to update your native implementation signatures to match the dispatched method call. See the mapping for [Android argument types](https://facebook.github.io/react-native/docs/native-modules-android#argument-types) and[iOS argument types](https://facebook.github.io/react-native/docs/native-modules-ios#argument-types) for reference. +In the example, the code-generated `Commands` will dispatch `moveToRegion` call to the native component’s view manager. In addition to writing the JS interface, you’ll need to update your native implementation signatures to match the dispatched method call. See the mapping for [Android argument types](https://facebook.github.io/react-native/docs/native-modules-android#argument-types) and[iOS argument types](https://facebook.github.io/react-native/docs/native-modules-ios#argument-types) for reference. **iOS** diff --git a/docs/new-architecture-library-ios.md b/docs/new-architecture-library-ios.md index 67a78515da1..8eca9aa3184 100644 --- a/docs/new-architecture-library-ios.md +++ b/docs/new-architecture-library-ios.md @@ -8,7 +8,7 @@ import NewArchitectureWarning from './\_markdown-new-architecture-warning.mdx'; -You have defined the JavaScript specs for your native modules as part of the [prerequisites](new-architecture-library-intro) and you are now ready to migrate your library to the New Architecture. Here are the steps you can follow to accomplish this. +You have defined the JavaScript specs for your native modules as part of the [prerequisites](new-architecture-library-intro), and you are now ready to migrate your library to the New Architecture. Here are the steps you can follow to accomplish this. ## 1. Updating your Podspec for the New Architecture @@ -42,11 +42,11 @@ Pod::Spec.new do |s| end ``` -## 2. Extend or implement the code-generated native interfaces +## 2. Extend or Implement the Code-generated Native Interfaces -The JavaScript spec for your native module or component will be used to generate native interface code for each supported platform (i.e. Android and iOS). These native interface files will be generated when a React Native application that depends on your library is built. +The JavaScript spec for your native module or component will be used to generate native interface code for each supported platform (i.e., Android and iOS). These native interface files will be generated when a React Native application that depends on your library is built. -While this generated native interface code **will not ship as part of your library**, you do need to make sure your Objective-C or Java code conforms to the protocols provided by these native interface files. You can use the Codegen script to generate your library’s native interface code in order to use **as reference**. +While this generated native interface code **will not ship as part of your library**, you do need to make sure your Objective-C or Java code conforms to the protocols provided by these native interface files. You can use the Codegen script to generate your library’s native interface code in order to use it **as reference**. ```sh cd @@ -55,7 +55,7 @@ node node_modules/react-native/scripts/generate-artifacts.js \ --outputPath \ ``` -This command will generate the boilerplate code required by iOS in the output path provided as paramenter. +This command will generate the boilerplate code required by iOS in the output path provided as a parameter. The files that are output by the script **should not be committed**, but you’ll need to refer to them to determine what changes you need to make to your native modules in order for them to provide an implementation for each generated `@protocol` / native interface. @@ -83,4 +83,4 @@ RCT_EXPORT_METHOD(getString:(NSString *)string } ``` -For an existing native module, you will likely already have one or more instances of [`RCT_EXPORT_METHOD`](native-modules-ios#export-a-native-method-to-javascript). To migrate to the New Architecture, you’ll need to make sure the method signature makes use of the structs provided by the codegen output. +For an existing native module, you will likely already have one or more instances of [`RCT_EXPORT_METHOD`](native-modules-ios#export-a-native-method-to-javascript). To migrate to the New Architecture, you’ll need to make sure the method signature uses the structs provided by the Codegen output. diff --git a/docs/the-new-architecture/backward-compatibility-fabric-components.md b/docs/the-new-architecture/backward-compatibility-fabric-components.md index 8226a24730f..64f93c1834f 100644 --- a/docs/the-new-architecture/backward-compatibility-fabric-components.md +++ b/docs/the-new-architecture/backward-compatibility-fabric-components.md @@ -12,14 +12,14 @@ import NewArchitectureWarning from '../\_markdown-new-architecture-warning.mdx'; :::info -The creation of a backward compatible Fabric Component requires the knowledge of how to create a Fabric Component. To recall these concepts, have a look at this [guide](pillars-fabric-components). +Creating a backward compatible Fabric Component requires the knowledge of how to create a Fabric Component. To recall these concepts, have a look at this [guide](pillars-fabric-components). -Fabric Components only work when the New Architecture is properly setup. If you already have a library that you want to migrate to the New Architecture, have a look at the [migration guide](../new-architecture-intro) as well. +Fabric Components only work when the New Architecture is properly set up. If you already have a library that you want to migrate to the New Architecture, have a look at the [migration guide](../new-architecture-intro) as well. ::: -Creating a backward compatible Fabric Component lets your users continue leverage your library, independently from the architecture they use. The creation of such a component requires a few steps: +Creating a backward compatible Fabric Component lets your users continue to leverage your library independently from the architecture they use. The creation of such a component requires a few steps: -1. Configure the library so that dependencies are prepared set up properly for both the Old and the New Architecture. +1. Configure the library so that dependencies are prepared to set up properly for both the Old and the New Architecture. 1. Update the codebase so that the New Architecture types are not compiled when not available. 1. Uniform the JavaScript API so that your user code won't need changes. @@ -31,7 +31,7 @@ While the last step is the same for all the platforms, the first two steps are d ### iOS -The Apple platform installs Fabric Components using [Cocoapods](https://cocoapods.org) as dependency manager. +The Apple platform installs Fabric Components using [Cocoapods](https://cocoapods.org) as a dependency manager. Every Fabric Component defines a `podspec` that looks like this: @@ -107,7 +107,7 @@ This `if` guard prevents the dependencies from being installed when the environm To create a module that can work with both architectures, you need to configure Gradle to choose which files need to be compiled depending on the chosen architecture. This can be achieved by using **different source sets** in the Gradle configuration. :::note -Please note that this is currently the suggested approach. While it might lead to some code duplication, it will ensure the maximum compatibility with both architectures. You will see how to reduce the duplication in the next section. +Please note that this is currently the suggested approach. While it might lead to some code duplication, it will ensure maximum compatibility with both architectures. You will see how to reduce the duplication in the next section. ::: To configure the Fabric Component so that it picks the proper sourceset, you have to update the `build.gradle` file in the following way: @@ -136,11 +136,11 @@ defaultConfig { } ``` -This changes do three main things: +These changes do three main things: 1. The first lines define a function that returns whether the New Architecture is enabled or not. 2. The `buildConfigField` line defines a build configuration boolean field called `IS_NEW_ARCHITECTURE_ENABLED`, and initialize it using the function declared in the first step. This allows you to check at runtime if a user has specified the `newArchEnabled` property or not. -3. The last lines leverage the function declared in step one to decide which source sets we need to build, depending on the choosen architecture. +3. The last lines leverage the function declared in step one to decide which source sets we need to build, depending on the chosen architecture. ## Update the codebase @@ -387,7 +387,7 @@ For a Fabric Component, the source of truth is the `NativeComponent. import MyComponent from 'your-component/src/index'; ``` -The **goal** is to conditionally `export` from the `index` file the proper object, given the architecture chosen by the user. We can achieve this with a code that looks like this: +The **goal** is to conditionally `export` the proper object from the `index` file , given the architecture chosen by the user. We can achieve this with a code that looks like this: NativeComponent` spec to access the Fabric Component. +- If that object is `null`, then the app has not enabled the Fabric feature. It's running on the Old Architecture, and the fallback is to use the default Native Components implementation ([iOS](../native-components-ios) or [Android](../native-components-android)). +- If that object is set, the app is running with Fabric enabled, and it should use the `NativeComponent` spec to access the Fabric Component. diff --git a/docs/the-new-architecture/backward-compatibility-turbomodules.md b/docs/the-new-architecture/backward-compatibility-turbomodules.md index 42d8a1cbc87..9b636d4fb79 100644 --- a/docs/the-new-architecture/backward-compatibility-turbomodules.md +++ b/docs/the-new-architecture/backward-compatibility-turbomodules.md @@ -12,12 +12,12 @@ import NewArchitectureWarning from '../\_markdown-new-architecture-warning.mdx'; :::info -The creation of a backward compatible TurboModule requires the knowledge of how to create a TurboModule. To recall these concepts, have a look at this [guide](pillars-turbomodules). +Creating a backward compatible TurboModule requires the knowledge of how to create a TurboModule. To recall these concepts, have a look at this [guide](pillars-turbomodules). -TurboModules only works when the New Architecture is properly setup. If you already have a library that you want to migrate to the New Architecture, have a look at the [migration guide](../new-architecture-intro) as well. +TurboModules only works when the New Architecture is properly set up. If you already have a library that you want to migrate to the New Architecture, have a look at the [migration guide](../new-architecture-intro) as well. ::: -Creating a backward compatible TurboModule lets your users continue leverage your library, independently from the architecture they use. The creation of such a module requires a few steps: +Creating a backward compatible TurboModule lets your users continue to leverage your library, independently from the architecture they use. The creation of such a module requires a few steps: 1. Configure the library so that dependencies are prepared set up properly for both the Old and the New Architecture. 1. Update the codebase so that the New Architecture types are not compiled when not available. @@ -31,7 +31,7 @@ While the last step is the same for all the platforms, the first two steps are d ### iOS -The Apple platform installs TurboModules using [Cocoapods](https://cocoapods.org) as dependency manager. +The Apple platform installs TurboModules using [Cocoapods](https://cocoapods.org) as a dependency manager. Every TurboModule defines a `podspec` that looks like this: @@ -87,7 +87,7 @@ pod install RCT_NEW_ARCH_ENABLED=1 pod install ``` -Therefore, we can leverage this environment variable in the `podspec` to exclude the settings and the dependencies that are related to the New Architecture: +Therefore, we can leverage this environment variable in the `podspec` to exclude the settings and the dependencies, that are related to the New Architecture: ```diff + if ENV['RCT_NEW_ARCH_ENABLED'] == '1' then @@ -142,7 +142,7 @@ This changes do three main things: 1. The first lines define a function that returns whether the New Architecture is enabled or not. 2. The `buildConfigField` line defines a build configuration boolean field called `IS_NEW_ARCHITECTURE_ENABLED`, and initialize it using the function declared in the first step. This allows you to check at runtime if a user has specified the `newArchEnabled` property or not. -3. The last lines leverage the function declared in step one to decide which source sets we need to build, depending on the choosen architecture. +3. The last lines leverage the function declared in step one to decide which source sets we need to build, depending on the chosen architecture. ## Update the codebase @@ -150,7 +150,7 @@ This changes do three main things: The second step is to instruct Xcode to avoid compiling all the lines using the New Architecture types and files when we are building an app with the Old Architecture. -The file to change is the module implementation file, which is usually a `.mm` file. That file is structured as follow: +The file to change is the module implementation file, which is usually a `.mm` file. That file is structured as follows: - Some `#import` statements, among which there is a `.h` file. - The module implementation, using the various `RCT_EXPORT_xxx` and `RCT_REMAP_xxx` macros. @@ -222,7 +222,7 @@ my-module └── package.json ``` -The code that should go in the `MyModuleImpl.java` and that can be shared by the Native Module and the TurboModule is, for example: +The code that should go in the `MyModuleImpl.java`, and that can be shared by the Native Module and the TurboModule is, for example: ```java title="example of MyModuleImple.java" package com.MyModule; @@ -319,7 +319,7 @@ For a TurboModule, the source of truth is the `Native.js` (or `.ts`) s import MyModule from 'your-module/src/index'; ``` -The **goal** is to conditionally `export` from the `index` file the proper object, given the architecture chosen by the user. We can achieve this with a code that looks like this: +The **goal** is to conditionally `export` the proper object from the `index` file , given the architecture chosen by the user. We can achieve this with a code that looks like this: :::note -If you are using TypeScript and you want to follow the example, make sure to `export` the `NativeModule` in a separate `ts` file called `.ts`. +If you are using TypeScript and you want to follow the example, ensure to `export` the `NativeModule` in a separate `ts` file called `.ts`. ::: Whether you are using Flow or TypeScript for your specs, we understand which architecture is running by checking whether the `global.__turboModuleProxy` object has been set or not. :::caution -The `global.__turboModuleProxy` API may change in the future for a function that encapsulate this check. +The `global.__turboModuleProxy` API may change in the future for a function that encapsulates this check. ::: - If that object is `null`, the app has not enabled the TurboModule feature. It's running on the Old Architecture, and the fallback is to use the default [`NativeModule` implementation](../native-modules-intro). -- If that object is set, the app is running with the TurboModules enabled and it should use the `Native` spec to access the TurboModule. +- If that object is set, the app is running with the TurboModules enabled, and it should use the `Native` spec to access the TurboModule. diff --git a/docs/the-new-architecture/landing-page.md b/docs/the-new-architecture/landing-page.md index 403a1dee659..fd8abf53fcf 100644 --- a/docs/the-new-architecture/landing-page.md +++ b/docs/the-new-architecture/landing-page.md @@ -7,23 +7,23 @@ import NewArchitectureWarning from '../\_markdown-new-architecture-warning.mdx'; -Starting from version 0.68, React Native provides the New Architecture, which offers developers new capabilities for building highly performant and responsive apps. Visit [Why a New Architecture](why) to learn more about what drove the decision to re-architect, and the benefits it provides. +Starting from version 0.68, React Native provides the New Architecture, which offers developers new capabilities for building highly performant and responsive apps. Visit [Why a New Architecture](why) to learn more about what drove the decision to re-architect and the benefits it provides. -In order to achieve these benefits, we had to rethink how Native Modules and Native Components work. This led us to develop the [Pillars of the New Architecture](pillars): +To achieve these benefits, we had to rethink how Native Modules and Native Components work. This led us to develop the [Pillars of the New Architecture](pillars): - [TurboModules](pillars-turbomodules), a framework to support efficient and flexible integration with native code - [Fabric renderer and components](pillars-fabric-components), which offer improved capabilities, cross-platform consistency, and performance in rendering -- [Codegen](pillars-codegen), which generates boilerplate C++ required by the New Architecture, via static typing in JavaScript +- [Codegen](pillars-codegen), which generates boilerplate C++ required by the New Architecture via static typing in JavaScript -## Get started with the New Architecture +## Get Started with the New Architecture -### For app developers +### For App Developers To **create a new app** using the New Architecture, head over to [Creating a New Architecture App](use-app-template), which will get you up and running in a few quick steps with the new app template. To **migrate an existing app** to the New Architecture, follow [Adopting the New Architecture](../new-architecture-intro). -### For library maintainers +### For Library Maintainers First, read up on the core concepts outlined in the [Pillars](pillars) section. diff --git a/docs/the-new-architecture/pillars-codegen.md b/docs/the-new-architecture/pillars-codegen.md index 11bd5062190..d736c340546 100644 --- a/docs/the-new-architecture/pillars-codegen.md +++ b/docs/the-new-architecture/pillars-codegen.md @@ -9,17 +9,17 @@ import NewArchitectureWarning from '../\_markdown-new-architecture-warning.mdx'; import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; import constants from '@site/core/TabsConstants'; -The **Codegen** is not a proper pillar, but it is a tool that can be used to avoid writing of a lot of repetitive code. Using the **Codegen** is not mandatory: all the code that is generated by it can also be written manually. However, it generates scaffolding code that could save you a lot of time. +The **Codegen** is not a proper pillar, but it is a tool that can be used to avoid writing a lot of repetitive code. Using **Codegen** is not mandatory: all the code that is generated by it can also be written manually. However, it generates scaffolding code that could save you a lot of time. -The **Codegen** is invoked automatically by React Native every time an iOS or an Android app is built. Occasionally, you would like to run the scripts that generate the code manually to know which types and files are actually generated: this is a common scenario when developing [**TurboModules**](./pillars-turbomodules) and [**Fabric Components**](./pillars-fabric-components), for example. +The **Codegen** is invoked automatically by React Native every time an iOS or Android app is built. Occasionally, you would like to run the scripts that generate the code manually to know which types and files are actually generated: this is a common scenario when developing [**TurboModules**](./pillars-turbomodules) and [**Fabric Components**](./pillars-fabric-components), for example. -This guide teaches how to configure the **Codegen**, how to invoke it manually for each platform, and it describes the generated code. +This guide teaches how to configure the **Codegen**, and how to invoke it manually for each platform, and describes the generated code. # Prerequisites You always need a React Native app to generate the code properly, even when invoking the **Codegen** manually. -The **Codegen** process is tightly coupled with the build of the app and the scripts are located in the `react-native` NPM package. +The **Codegen** process is tightly coupled with the build of the app, and the scripts are located in the `react-native` NPM package. For the sake of this guide, create a project using the React Native CLI as follows: @@ -48,9 +48,9 @@ The rest of this guide assumes that you have a `TurboModule` and/or a `Fabric Co The **Codegen** for iOS relies on some Node scripts that are invoked during the build process. The scripts are located in the `MyApp/node_modules/react_native/scripts/` folder. -The script that you have to run is the `generate-artifacts.js` script. This searches among all the dependencies of the app, looking for JS files which respects some specific conventions (look at [TurboModules](pillars-turbomodules) and [Fabric Components](pillars-fabric-components) sections for details) and it generates the required code. +The script that you have to run is the `generate-artifacts.js` script. This searches among all the dependencies of the app, looking for JS files that respects some specific conventions (look at [TurboModules](pillars-turbomodules) and [Fabric Components](pillars-fabric-components) sections for details), and it generates the required code. -To invoke the script you can run this command from the root folder of your app: +To invoke the script, you can run this command from the root folder of your app: ```sh node node_modules/react_native/scripts/generate-artifacts.js \ @@ -58,7 +58,7 @@ node node_modules/react_native/scripts/generate-artifacts.js \ --outputPath \ ``` -Given that the app has `TurboModules` and/or `Fabric Components` configured as a dependency, the **Codegen** will look for all of them and it will generate the code in the path you provided. +Given that the app has `TurboModules` and/or `Fabric Components` configured as a dependency, **Codegen** looks for all of them and generates the code in the path you provided. ## The Generated Code @@ -100,9 +100,9 @@ codegen └── ShadowNodes.h ``` -The `codegen` folder sits at the root of the hierarchy, as expected. Nested into it there are two more folders: `build/generated`. +The `codegen` folder sits at the root of the hierarchy, as expected. Nested into it, there are two more folders: `build/generated`. -Then, there is an `ios` folder which contains: +Then, there is an `ios` folder that contains: - A custom folder for each TurboModule. - The header (`.h`) and implementation (`.mm`) files for the `RCTThirdPartyFabricComponentsProvider`. @@ -114,13 +114,13 @@ In the example above, there are both a TurboModule and a set of Fabric Component Each TurboModule's folder contains two files: an interface file and an implementation file. -The interface files have the same name of the TurboModule and they contain methods to initialize the JSI interface. +The interface files have the same name as that of the TurboModule and contain methods to initialize the JSI interface. -The implementation files, instead, have the `-generated` suffix and they contains the logic to invoke the native methods from JS and viceversa. +The implementation files, instead, have the `-generated` suffix and contain the logic to invoke the native methods from JS and vice-versa. ### Fabric Components -The content of each Fabric Component folder contains several files. The basic element for a Fabric Componenent is the `ShadowNode`: it represents a node in the React absract tree. The `ShadowNode` represents a React entity, therefore it could need some props, which are defined in the `Props` files and, sometimes, an `EventEmitter`, defined in the corresponding file. +The content of each Fabric Component folder contains several files. The basic element for a Fabric Component is the `ShadowNode`: it represents a node in the React abstract tree. The `ShadowNode` represents a React entity; therefore, it could need some props, which are defined in the `Props` files and, sometimes, an `EventEmitter`, defined in the corresponding file. Additionally, the **Codegen** also creates a `ComponentDescriptor.h` and an `RCTComponentViewHelpers.h` files: the first one is used by React Native and Fabric to properly get a reference to the Component, while the latter contains some helper methods and protocols that can be implemented by the Native View to properly respond to JSI invocations. @@ -128,13 +128,13 @@ For further details about how Fabric works, have a look at the [Renderer](/archi ### RCTThirdPartyFabricComponentsProvider -These are an interface and an implementation files for a registry. React Native uses this registry at runtime to retrieve the right class for a required Fabric Component. Once React Native has an handle to that class, it can instantiate it. +These are interface and implementation files for a registry. React Native uses this registry at runtime to retrieve the right class for a required Fabric Component. Once React Native has a handle to that class, it can instantiate it. # Android ## Running the Codegen -Android `Codegen` relies on a Gradle task to generate the required code. First, you need to configure the Android app to work with the New Architecture, otherwise the Gradle task fails. +Android `Codegen` relies on a Gradle task to generate the required code. First, you need to configure the Android app to work with the New Architecture; otherwise, the Gradle task fails. 1. Open the `MyApp/android/gradle.properties` file. 1. Flip the `newArchEnabled` flag from `false` to `true`. @@ -145,7 +145,7 @@ After that, you can navigate into the `SampleApp/android` folder and run: ./gradlew generateCodegenArtifactsFromSchema ``` -This tasks invokes the `generateCodegenArtifactsFromSchema` on all the the imported projects of the app (the app and all the node modules which are linked to it). It generates the code in the corresponding `node_modules/` folder. So, for example, if you have a Fabric Component whose node module is called `my-fabric-component`, the generated code is located in the `SampleApp/node_modules/my-fabric-component/android/build/generated/source/codegen` path. +These tasks invoke the `generateCodegenArtifactsFromSchema` on all the the imported projects of the app (the app and all the node modules which are linked to it). It generates the code in the corresponding `node_modules/` folder. So, for example, if you have a Fabric Component whose node module is called `my-fabric-component`, the generated code is located in the `SampleApp/node_modules/my-fabric-component/android/build/generated/source/codegen` path. ## The Generated Code @@ -213,20 +213,20 @@ codegen -Java can't interoperate seamlessly with C++ as Objective-C++ does. To work properly, the **Codegen** creates some bridging between the Java and the C++ world in the `jni` folder, where the Java Native Interfaces are defined. +Java can't interoperate seamlessly with C++ as Objective-C++ does. To work properly, **Codegen** creates some bridging between the Java and the C++ world in the `jni` folder, where the Java Native Interfaces are defined. -Notice that both TurboModules and Fabric Components comes with two build file descriptors: the `Android.mk` and the `CMakeLists.txt`. These are used by the Android app to actually build the external modules. +Notice that both TurboModules and Fabric Components come with two build file descriptors: the `Android.mk` and the `CMakeLists.txt`. These are used by the Android app to actually build the external modules. ### TurboModule -The **Codegen** generates a Java abstract class in the `java` package with the same name of the TurboModule. This abstract class has to be implemented by the JNI C++ implementation. +The **Codegen** generates a Java abstract class in the `java` package with the same name as that of the TurboModule. This abstract class has to be implemented by the JNI C++ implementation. -Then, it generates the C++ files in the `jni` folder. They follow the same iOS convention: there is an interface called `MyTurbomodule.h` and an implementation file called `MyTurbomodule-generated.cpp`. The former is an interface that allows React Natvie to initialize the JSI interface for the TurboModule. The latter is the implementation file which contains the logic to invoke the native method from JS and viceversa. +Then, it generates the C++ files in the `jni` folder. They follow the same iOS convention: there is an interface called `MyTurbomodule.h` and an implementation file called `MyTurbomodule-generated.cpp`. The former is an interface that allows React Native to initialize the JSI interface for the TurboModule. The latter is the implementation file which contains the logic to invoke the native method from JS and vice-versa. ### Fabric Component The **Codegen** for a Fabric Component contains a `MyFabricComponentManagerInterface.java` and a `MyFabricComponentManagerDelegate.java` in the `java` package. They are implemented and used by the native `MyFabricComponentManager` required to properly load the component at runtime (See the guide on how to create a [Fabric Component](./pillars-fabric-components) for details). -Then, there is a layer of JNI C++ files that are used by Fabric to render the components. The basic element for a Fabric Componenent is the `ShadowNode`: it represents a node in the React absract tree. The `ShadowNode` represents a React entity, therefore it could need some props, which are defined in the `Props` files and, sometimes, an `EventEmitter`, defined in the corresponding file. +Then, there is a layer of JNI C++ files that are used by Fabric to render the components. The basic element for a Fabric Component is the `ShadowNode`: it represents a node in the React abstract tree. The `ShadowNode` represents a React entity; therefore it could need some props, which are defined in the `Props` files and, sometimes, an `EventEmitter`, defined in the corresponding file. -The **Codegen** also creates a `ComponentDescriptor.h` which is required to get a proper handle to the Fabric Component. +The **Codegen** also creates a `ComponentDescriptor.h`, which is required to get a proper handle on the Fabric Component. diff --git a/docs/the-new-architecture/pillars-fabric-components.md b/docs/the-new-architecture/pillars-fabric-components.md index a4271e49985..fa9fd98321c 100644 --- a/docs/the-new-architecture/pillars-fabric-components.md +++ b/docs/the-new-architecture/pillars-fabric-components.md @@ -12,7 +12,7 @@ import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; import con A Fabric Component is a UI component rendered on the screen using the [Fabric Renderer](https://reactnative.dev/architecture/fabric-renderer). Using Fabric Components instead of Native Components allows us to reap all the [benefits](./why) of the **New Architecture**: - Strongly typed interfaces that are consistent across platforms. -- The ability to write your code in C++, either exclusively or integrated with another native platform language, reducing the need to duplicate implementations across platforms. +- The ability to write your code in C++, either exclusively or integrated with another native platform language, hence reducing the need to duplicate implementations across platforms. - The use of JSI, a JavaScript interface for native code, which allows for more efficient communication between native and JavaScript code than the bridge. A Fabric Component is created starting from a **JavaScript specification**. Then [**Codegen**](./pillars-codegen) creates some C++ scaffolding code to connect the component-specific logic (for example, accessing some native platform capability) to the rest of the React Native infrastructure. The C++ code is the same for all the platforms. Once the component is properly connected with the scaffolding code, it is ready to be imported and used by an app. @@ -32,17 +32,17 @@ To create a Fabric Component, you have to follow these steps: 2. Configure the component so that **Codegen** can create the shared code and it can be added as a dependency for an app. 3. Write the required native code. -Once these steps are done, the component is ready to be consumed by an app. The guide shows how to add it to an app, leveraging _autolinking_, and how to reference it from the JavaScript code. +Once these steps are done, the component is ready to be consumed by an app. The guide shows how to add it to an app by leveraging _autolinking_, and how to reference it from the JavaScript code. ## 1. Folder Setup -In order to keep the component decoupled from the app, it's a good idea to define the module separately from the app, and then add it as a dependency to your app later. This is also what you'll do for writing Fabric Component that can be released as open-source libraries later. +In order to keep the component decoupled from the app, it's a good idea to define the module separately from the app and then add it as a dependency to your app later. This is also what you'll do for writing Fabric Component that can be released as open-source libraries later. For this guide, you are going to create a Fabric Component that centers some text on the screen. Create a new folder at the same level of the app and call it `RTNCenteredText`. -In this folder, create three subfolders: `js`, `ios` and `android`. +In this folder, create three subfolders: `js`, `ios`, and `android`. The final result should look like this: @@ -108,7 +108,7 @@ export default codegenNativeComponent( -At the beginning of the spec files, there are the imports. The most important imports, required by every Fabric Component, are: +At the beginning of the spec files, there are the imports. The most important imports, required by every Fabric Component are: - The `HostComponent`: type the exported component needs to conform to. - The `codegenNativeComponent` function: responsible to actually register the component in the JavaScript runtime. @@ -226,9 +226,9 @@ Pod::Spec.new do |s| end ``` -The `.podspec` file has to be a sibling of the `package.json` file and its name is the one we set in the `package.json`'s `name` property: `rtn-centered-text`. +The `.podspec` file has to be a sibling of the `package.json` file, and its name is the one we set in the `package.json`'s `name` property: `rtn-centered-text`. -The first part of the file prepares some variables we will use throughout the rest of it. Then, there is a section that contains some information used to configure the pod, like its name, version, and description. Finally, we have a set of dependencies that are required by the New Architecture. +The first part of the file prepares some variables we will use throughout the rest of it. Then, there is a section that contains some information used to configure the pod, like its name, version, and description. Finally, we have a set of dependencies that the New Architecture requires. ### Android: `build.gradle`, `AndroidManifest.xml`, a `ReactPackage` class @@ -350,9 +350,9 @@ The last step requires you to write some native code to connect the JavaScript s 1. Run **Codegen** to see what would be generated. 2. Write the native code that will make it work. -When developing a React Native app that uses a Fabric Component, it is responsibility of the app to actually generate the code using **Codegen**. However, when developing a Fabric Component as a library, it needs to reference the generated code and it is useful to see what the app will generate. +When developing a React Native app that uses a Fabric Component, it is the responsibility of the app to actually generate the code using **Codegen**. However, when developing a Fabric Component as a library, it needs to reference the generated code, and it is useful to see what the app will generate. -As first step for both iOS and Android, this guide shows how to execute manually the scripts used by **Codegen** to generate the required code. Further information on **Codegen** can be found [here](./pillars-codegen.md) +As the first step for both iOS and Android, this guide shows how to execute manually the scripts used by **Codegen** to generate the required code. Further information on **Codegen** can be found [here](./pillars-codegen.md). :::caution The code generated by **Codegen** in this step should not be committed to the versioning system. React Native apps are able to generate the code when the app is built. This allows an app to ensure that all libraries have code generated for the correct version of React Native. @@ -456,14 +456,14 @@ RCT_EXPORT_VIEW_PROPERTY(text, NSString) @end ``` -This file is the manager for the Fabric Component. The manager objects are used by the React Native runtime to register the modules, the properties and the methods so that they are available to the JavaScript side. +This file is the manager for the Fabric Component. React Native runtime uses manager objects to register the modules, properties and methods to make them available to the JavaScript side. -The most important call is to the `RCT_EXPORT_MODULE` which is required to export the module so that Fabric can retrieve and instantiate it. +The most important call is to the `RCT_EXPORT_MODULE`, which is required to export the module so that Fabric can retrieve and instantiate it. Then, you have to expose the `text` property for the Fabric Component. This is done with the `RCT_EXPORT_VIEW_PROPERTY` macro, specifying a name and a type. :::info -There are other macros that can be used to export custom properties, emitters and other constructs. You can view the code that specifies them [here](https://github.com/facebook/react-native/blob/main/React/Views/RCTViewManager.h) +There are other macros that can be used to export custom properties, emitters, and other constructs. You can view the code that specifies them [here](https://github.com/facebook/react-native/blob/main/React/Views/RCTViewManager.h). ::: ##### RTNCenteredText.h @@ -561,17 +561,17 @@ Class RTNCenteredTextCls(void) This file contains the actual implementation of the view. -It starts with some imports which require you to read the files generated by **Codegen**. +It starts with some imports, which require you to read the files generated by **Codegen**. -The component has to conform to a specific protocol generated by **Codegen**, in this case `RCTRTNCenteredTextViewProtocol`. +The component has to conform to a specific protocol generated by **Codegen**, in this case, `RCTRTNCenteredTextViewProtocol`. -Then, the file defines a static `(ComponentDescriptorProvider)componentDescriptorProvider` method which is used by Fabric to retrieve the descriptor provider to instantiate the object. +Then, the file defines a static `(ComponentDescriptorProvider)componentDescriptorProvider` method which Fabric uses to retrieve the descriptor provider to instantiate the object. -Then, there is the constructor of the view: the `init` method. In this method, it is important to create a `defaultProps` struct using the `RTNCenteredTextProps` type from **Codegen**. You need to assign it to the private `_props` property to correctly initialize the Fabric Component. The remaining part of the initializer is standard Objective-C code to create views and layout them with AutoLayout. +Then, there is the constructor of the view: the `init` method. In this method, it is important to create a `defaultProps` struct using the `RTNCenteredTextProps` type from **Codegen**. You need to assign it to the private `_props` to initialize the Fabric Component correctly. The remaining part of the initializer is standard Objective-C code to create views and layout them with AutoLayout. The last two pieces are the `updateProps` method and the `RTNCenteredTextCls` method. -The `updateProps` method is invoked by Fabric every time a prop changes in JavaScript. The props passed as parameters are downcasted to the proper `RTNCenteredTextProps` type and then they are used to update the native code if needed. Notice that the superclass method `[super updateProps]` must be invoked as the last statement of this method, otherwise the `props` and `oldProps` struct will have the same values and you'll not be able to use them to make decisions and to update the component. +The `updateProps` method is invoked by Fabric every time a prop changes in JavaScript. The props passed as parameters are downcasted to the proper `RTNCenteredTextProps` type, and then they are used to update the native code if needed. Notice that the superclass method `[super updateProps]` must be invoked as the last statement of this method; otherwise the `props` and `oldProps` struct will have the same values, and you'll not be able to use them to make decisions and to update the component. Finally, the `RTNCenteredTextCls` is another static method used to retrieve the correct instance of the class at runtime. diff --git a/docs/the-new-architecture/pillars-turbomodule.md b/docs/the-new-architecture/pillars-turbomodule.md index 77159a4fc24..b5afb3952ed 100644 --- a/docs/the-new-architecture/pillars-turbomodule.md +++ b/docs/the-new-architecture/pillars-turbomodule.md @@ -15,7 +15,7 @@ TurboModules are the next iteration on Native Modules that provide a few extra [ - Strongly typed interfaces that are consistent across platforms - The ability to write your code in C++, either exclusively or integrated with another native platform language, reducing the need to duplicate implementations across platforms - Lazy loading of modules, allowing for faster app startup -- The use of JSI, a JavaScript interface for native code, which allows for more efficient communication between native and JavaScript code than the bridge +- The use of JSI, a JavaScript interface for native code, allows for more efficient communication between native and JavaScript code than the bridge This guide will show you how to create a basic TurboModule. @@ -34,7 +34,7 @@ To create a TurboModule, we need to: ## 1. Folder Setup -In order to keep the module decoupled from the app, it's a good idea to define the module separately from the app, and then add it as a dependency to your app later. This is also what you'll do for writing TurboModules that can be released as open-source libraries later. +In order to keep the module decoupled from the app, it's a good idea to define the module separately from the app and then add it as a dependency to your app later. This is also what you'll do for writing TurboModules that can be released as open-source libraries later. Next to your application, create a folder called `RTNCalculator`. **RTN** stands for "**R**eac**t** **N**ative", and is a recommended prefix for React Native modules. @@ -100,7 +100,7 @@ At the beginning of the spec files are the imports: - The `TurboModule` type, which defines the base interface for all TurboModules - The `TurboModuleRegistry` JavaScript module, which contains functions for loading TurboModules -The second section of the file contains the interface specification for the TurboModule. In this case, the interface defines the `add` function which takes two numbers and returns a promise that resolves to a number. This interface type **must** be named `Spec` for a TurboModule. +The second section of the file contains the interface specification for the TurboModule. In this case, the interface defines the `add` function, which takes two numbers and returns a promise that resolves to a number. This interface type **must** be named `Spec` for a TurboModule. Finally, we invoke `TurboModuleRegistry.get`, passing the module's name, which will load the TurboModule if it's available. @@ -112,11 +112,11 @@ We are writing JavaScript files importing types from libraries, without setting Next, you need to add some configuration for [**Codegen**](pillars-codegen.md) and auto-linking. -Some of these configuration files are shared between iOS and Android, while the others are platform-specific. +Some configuration files are shared between iOS and Android, while the others are platform-specific. ### Shared -The shared configuration is a `package.json` file that will be used by yarn when installing your module. Create the `package.json` file in the root of the `RTNCalculator` directory. +The shared configuration is a `package.json` file used by yarn when installing your module. Create the `package.json` file in the root of the `RTNCalculator` directory. ```json title="package.json" { @@ -160,20 +160,20 @@ The shared configuration is a `package.json` file that will be used by yarn when } ``` -The upper part of the file contains some descriptive information like the name of the component, its version and its source files. Make sure to update the various placeholders which are wrapped in `<>`: replace all the occurrences of the ``, ``, and `` tokens. +The upper part of the file contains some descriptive information like the name of the component, its version, and its source files. Make sure to update the various placeholders which are wrapped in `<>`: replace all the occurrences of the ``, ``, and `` tokens. Then there are the dependencies for this package. For this guide, you need `react` and `react-native`. Finally, the **Codegen** configuration is specified by the `codegenConfig` field. It contains an array of libraries, each of which is defined by three other fields: - `name`: The name of the library. By convention, you should add the `Spec` suffix. -- `type`: The type of module contained by this package. In this case, it is a TurboModule, thus the value to use is `modules`. +- `type`: The type of module contained by this package. In this case, it is a TurboModule; thus, the value to use is `modules`. - `jsSrcsDir`: the relative path to access the `js` specification that is parsed by **Codegen**. - `android.javaPackageName`: the package to use in the Java files generated by **Codegen**. ### iOS: Create the `podspec` file -For iOS, you'll need to create a `rtn-calculator.podspec` file which will define the module as a dependency for your app. It will stay in the root of `RTNCalculator`, alongside the `ios` folder. +For iOS, you'll need to create a `rtn-calculator.podspec` file, which will define the module as a dependency for your app. It will stay in the root of `RTNCalculator`, alongside the `ios` folder. The file will look like this: @@ -215,7 +215,7 @@ Pod::Spec.new do |s| end ``` -The `.podspec` file has to be a sibling of the `package.json` file and its name is the one we set in the `package.json`'s `name` property: `rtn-calculator`. +The `.podspec` file has to be a sibling of the `package.json` file, and its name is the one we set in the `package.json`'s `name` property: `rtn-calculator`. The first part of the file prepares some variables we will use throughout the rest of it. Then, there is a section that contains some information used to configure the pod, like its name, version, and description. Finally, we have a set of dependencies that are required by the New Architecture. @@ -225,7 +225,7 @@ To prepare Android to run **Codegen** you have to create three files: 1. The `build.gradle` with the **Codegen** configuration 1. The `AndroidManifest.xml` file -1. A java class that implements the `ReactPackage` interface. +1. A java class that implements the `ReactPackage` interface At the end of these steps, the `android` folder should look like this: @@ -325,7 +325,7 @@ public class CalculatorPackage extends TurboReactPackage { } ``` -The `ReactPackage` interface is used by React Native to understand what native classes the app has to use for the `ViewManager` and `Native Modules` exported by the library. +React Native uses the `ReactPackage` interface to understand what native classes the app has to use for the `ViewManager` and `Native Modules` exported by the library. ## 4. Native Code @@ -334,9 +334,9 @@ For the final step in getting your TurboModule ready to go, you'll need to write - Run **Codegen** to see what it generates. - Write your native code, implementing the generated interfaces. -When developing a React Native app that uses a TurboModule, it is responsibility of the app to actually generate the code using **Codegen**. However, when developing a TurboModule as a library, we need to reference the generated code, and it is therefore useful to see what the app will generate. +When developing a React Native app that uses a TurboModule, it is the responsibility of the app to actually generate the code using **Codegen**. However, when developing a TurboModule as a library, we need to reference the generated code, and it is therefore, useful to see what the app will generate. -As first step for both iOS and Android, this guide shows how to execute manually the scripts used by **Codegen** to generate the required code. Further information on **Codegen** can be found [here](pillars-codegen.md) +As the first step for both iOS and Android, this guide shows how to execute manually the scripts used by **Codegen** to generate the required code. Further information on **Codegen** can be found [here](pillars-codegen.md). :::caution The code generated by **Codegen** in this step should not be committed to the versioning system. React Native apps are able to generate the code when the app is built. This allows an app to ensure that all libraries have code generated for the correct version of React Native. @@ -395,7 +395,7 @@ The relevant path for the TurboModule interface is `generated/build/generated/io See the [Codegen](./pillars-codegen) section for further details on the generated files. :::note -When generating the scaffolding code using **Codegen**, iOS does not clean the `build` folder automatically. If you changed a the Spec name, for example, and then run **Codegen** again, the old files will be retained. +When generating the scaffolding code using **Codegen**, iOS does not clean the `build` folder automatically. If you changed the Spec name, for example, and then run **Codegen** again, the old files would be retained. If that happens, remember to remove the `build` folder before running the **Codegen** again. ``` @@ -472,7 +472,7 @@ Android follows similar steps to iOS. We have to generate the code for Android, #### Generate the Code - Android -To generate the code for Android, we need to manually invoke Codegen. This is done similarly to what we did for iOS: first, we need to add the package to the app and then we need to invoke a script. +To generate the code for Android, we need to manually invoke Codegen. This is done similarly to what we did for iOS: first, we need to add the package to the app, and then we need to invoke a script. ```sh title="Running Codegen for Android" cd MyApp diff --git a/docs/the-new-architecture/pillars.md b/docs/the-new-architecture/pillars.md index fdcfd555ac9..05a828af51c 100644 --- a/docs/the-new-architecture/pillars.md +++ b/docs/the-new-architecture/pillars.md @@ -7,16 +7,16 @@ import NewArchitectureWarning from '../\_markdown-new-architecture-warning.mdx'; -The New Architecture is composed mainly by two pillars: +The New Architecture is composed mainly of two pillars: - [TurboModules](pillars-turbomodules) - [Fabric Components](pillars-fabric-components). -TurboModules are the preferred way to create libraries that leverage some platform specific API. Fabric Components are the preferred way to create reusable UI components, providing a native experience to the users. +TurboModules are the preferred way to create libraries that leverage some platform-specific API. Fabric Components are the preferred way to create reusable UI components, providing a native experience to the users. The main goal of this section is to drive the reader through a step-by-step guide to create their first TurboModule or Fabric Component. -The next sections contain an high-level overview of the pillars, together with the steps to create them. To create one of these pillars, the steps are: +The next sections contain a high-level overview of the pillars and the steps to create them. To create one of these pillars, the steps are: 1. Define a JavaScript specification using Flow or TypeScript. 1. Configure the dependencies management system to generate code from the provided spec. @@ -26,7 +26,7 @@ The next sections contain an high-level overview of the pillars, together with t Finally, we dive a little deeper into the [Codegen](pillars-codegen) process that is required to create all the C++ types and files used by our components, including some useful steps to work comfortably while developing the component. :::caution -To integrate a TurboModule or a Fabric Component in an app, the app has to run with the New Architecture enabled. +The app has to run with the **New Architecture enabled to integrate a TurboModule or a Fabric Component** in an app. To create a new app adopting the New Architecture, refer to the [Using the App Template](use-app-template) section. To migrate an existing app to the New Architecture, refer to the [Migration](../new-architecture-intro) guide. diff --git a/docs/the-new-architecture/use-app-template.md b/docs/the-new-architecture/use-app-template.md index ca4ed3d3dad..50b82a1b20f 100644 --- a/docs/the-new-architecture/use-app-template.md +++ b/docs/the-new-architecture/use-app-template.md @@ -11,17 +11,17 @@ import NewArchitectureWarning from '../\_markdown-new-architecture-warning.mdx'; This page will help you create a new React Native app that uses the New Architecture. -## Development environment +## Development Environment -Before continuing, make sure you've followed all the steps in [Setting up the development environment](getting-started.md), under the **React Native CLI Quickstart** tab. +Before continuing, make sure you've followed all the steps in the[Setting up the development environment](getting-started.md) section under the **React Native CLI Quickstart** tab. If following the setup guide, stop when you reach the section **Running your React Native Application**, and resume following this guide. :::caution -If you're using Expo, you can't enable the New Architecture at the moment, and will have to wait for a future release of the Expo SDK. +If you're using Expo, you can't enable the New Architecture at the moment and will have to wait for a future release of the Expo SDK. ::: -## Creating a new application +## Creating a New Application @@ -43,7 +43,7 @@ Follow the steps below to enable the New Architecture and build the app. Hermes is an open-source JavaScript engine optimized for React Native. [Hermes will be the default engine in the future](https://github.com/reactwg/react-native-new-architecture/discussions/4), and we highly recommend you use it. -Please [follow the instructions on the React Native website](hermes.md) in order to enable Hermes in your application. +Please [follow the instructions on the React Native website](hermes.md) to enable Hermes in your application. ### Enable the New Architecture @@ -103,21 +103,21 @@ yarn android ``` :::note -You may notice longer build times with the New Architecture, due to additional step of C++ compilation with the Android NDK. To improve your build time, see [Speeding Up Your Build Phase](build-speed.md). +You may notice longer build times with the New Architecture due to additional step of C++ compilation with the Android NDK. To improve your build time, see [Speeding Up Your Build Phase](build-speed.md). ::: -### Confirming the New Architecture is in use +### Confirming the New Architecture is in Use -After you build and run the app, when Metro serves the JavaScript bundle, you should see `"fabric": true` in the Metro logs: +After you build and run the app when Metro serves the JavaScript bundle, you should see `"fabric": true` in the Metro logs: Metro shows fabric: true -### Want to know more? +### Want to Know More? -If you'd like to view the code changes relevant for the New Architecture, take a look at the [upgrade helper from version 0.67.4 to 0.68.0](https://react-native-community.github.io/upgrade-helper/?from=0.67.4&to=0.68.0). Files that were added for the New Architecture are marked with a yellow banner. +If you'd like to view the code changes relevant to the New Architecture, take a look at the [upgrade helper from version 0.67.4 to 0.68.0](https://react-native-community.github.io/upgrade-helper/?from=0.67.4&to=0.68.0). Files that were added for the New Architecture are marked with a yellow banner. For further explanations of what each file is doing, check out these guides to walk through the changes step-by-step: diff --git a/docs/the-new-architecture/why.md b/docs/the-new-architecture/why.md index 47bb4e7dd8e..84b8fe62e0e 100644 --- a/docs/the-new-architecture/why.md +++ b/docs/the-new-architecture/why.md @@ -1,44 +1,44 @@ --- id: why -title: Why A New Architecture +title: Why a New Architecture --- import NewArchitectureWarning from '../\_markdown-new-architecture-warning.mdx'; -The goal of the New Architecture is to solve some of the issues that afflicted the Old Architecture in terms of performance and flexibility. This section provides the basic context to understand the Old Architecture limitations and how it has been possible to overcome them with the New Architecture. +The goal of the New Architecture is to solve some of the issues that afflicted the Old Architecture in terms of performance and flexibility. This section provides the basic context to understand the Old Architecture's limitations and how it has been possible to overcome them with the New Architecture. This is not a technical deep dive: for further technical information, refer to the [Architecture](/architecture/overview) tab of the website. ## Old Architecture's Issues -The Old Architecture used to work by serializing all the data that has to be passed from the JS layer to the native layer using a component called _The Bridge_. _The Bridge_ can be imagined as a bus where the producer layer sent some data for the consumer layer. The consumer could read the data, deserialize it and execute the required operations. +The Old Architecture used to work by serializing all the data that had to be passed from the JS layer to the native layer using a component called _The Bridge_. _The Bridge_ can be imagined as a bus where the producer layer sends some data for the consumer layer. The consumer could read the data, deserialize it and execute the required operations. _The Bridge_ had some intrinsic limitations: - **It was asynchronous:** one layer submitted the data to the bridge and asynchronously "waited" for the other layer to process them, even when this was not really necessary. -- **It was single threaded:** JS used to work on a single thread, therefore the computation that happened in that world had to be performed on that single thread. -- **It imposed extra overheads:** everytime one layer had to use the other one, it had to serialize some data. The other layer had to deserialize them. The chosen format was JSON, for its simplicity and human-readability, but despite being lightweight, it was a cost to pay. +- **It was single-threaded:** JS used to work on a single thread; therefore, the computation that happened in that world had to be performed on that single thread. +- **It imposed extra overheads:** every time one layer had to use the other one, it had to serialize some data. The other layer had to deserialize them. The chosen format was JSON for its simplicity and human-readability, but despite being lightweight, it was a cost to pay. ## New Architecture's Improvements -The New Architecture dropped the concept of _The Bridge_ in favor of another communication mechanism: the _JavaScript Interface (JSI)_. The _JSI_ is an interface that allows a JavaScript object to hold a reference to a C++ and viceversa. +The New Architecture dropped the concept of _The Bridge_ in favor of another communication mechanism: the _JavaScript Interface (JSI)_. The _JSI_ is an interface that allows a JavaScript object to hold a reference to a C++ and vice-versa. Once an object has a reference to the other one, it can directly invoke methods on it. So, for example, a C++ object can now ask a JavaScript object to execute a method in the JavaScript world and viceversa. -This idea allowed to unlock several benefits: +This idea allowed the unlocking of several benefits: -- **Synchronous execution:** it is now possibile to execute synchronously those functions that should not have been asynchronous in the first place. -- **Concurrency:** it is possible from JavaScript to invoke functions that are executed on different thread. -- **Lower overhead:** the New Architecture don't have to serialize/deserialize the data anymore, therefore there are no serialization taxes to pay. -- **Code sharing:** by introducing C++, it is now possible to abstract all the platform agnostic code and to share it with ease between the plaforms. -- **Type safety:** to make sure that JS can properly invoke methods on C++ objects and viceversa, a layer of code automatically generated has been added. The code is generated starting from some JS specification that must be typed through Flow or TypeScript. +- **Synchronous execution:** it is now possible to execute synchronously those functions that should not have been asynchronous in the first place. +- **Concurrency:** it is possible from JavaScript to invoke functions that are executed on different threads. +- **Lower overhead:** the New Architecture doesn't have to serialize/deserialize the data anymore; therefore there are no serialization taxes to pay. +- **Code sharing:** by introducing C++, it is now possible to abstract all the platform agnostic code and to share it with ease between the platforms. +- **Type safety:** to make sure that JS can properly invoke methods on C++ objects and vice-versa, a layer of code automatically generated has been added. The code is generated starting from some JS specification that must be typed through Flow or TypeScript. -These advantages are the foundations of the [TurboModule](pillars-turbomodules) system and a jumping stone to further enhancements. For example, it has been possible to develop a new renderer which is faster and more performant: [Fabric](/architecture/fabric-renderer) and its [Fabric Components](pillars-fabric-components). +These advantages are the foundations of the [TurboModule](pillars-turbomodules) system and a jumping stone to further enhancements. For example, it has been possible to develop a new renderer that is faster and more performant: [Fabric](/architecture/fabric-renderer) and its [Fabric Components](pillars-fabric-components). ## Further Reading -For a technical overview of the New Architecture, have a look at the [Architecture tab](/architecture/overview). +For a technical overview of the New Architecture, read the [Architecture tab](/architecture/overview). -For more information on the Fabric Renderer, have a look at the [Fabric section](/architecture/fabric-renderer). +For more information on the Fabric Renderer, read the [Fabric section](/architecture/fabric-renderer).