Introduction to install

For details about how to install React Native, see the React Native official documentation.

NodeJS Knowledge base: See NodeJS Introduction. (Respect the knowledge, please buy the original).

Book: React Native: How to React Native

Code example: Learn React Native in 30 days

React Native uses React Native.

React and React Native and NodeJS

React is a javascript library developed by Facebook for developing user interfaces. The source code is maintained by the best programmers at Facebook and the community. React introduces many new things, such as componentization, JSX, virtual DOM, etc. The virtual DOM allows us to render components very quickly, freeing us from the heavy workload of constantly manipulating the DOM. It does more work on the V layer in MVC, and combined with other things like Flux, you can easily build powerful applications.

In the React world, everything is a component. You can build any component that doesn’t exist in direct HTML, such as drop-down menus, navigation menus, and so on. Components can also contain other components. Each component has a Render method that renders the component. At the same time, each component has its own scope, which is defined from other components and used to build methods belonging to the component for easy reuse. JSX is a JS-BASED extension that allows you to write HTML directly in JS instead of having to concatenate a bunch of strings to write HTML in JS like we used to. React Does not operate on the DOM directly. Frequent DOM operations affect performance and experience. React stores the DOM structure in memory, compares it to the return value of the Render method, uses its free-form diff algorithm to calculate the difference, and then reflects it into the real DOM. That is, most of the time we render components, change their state, and so on are virtual DOM manipulations, and only in the case of changes are they reflected in the real DOM. React Native is based on ReacJS and brings the capabilities of the React programming model to mobile development for iOS and Android Native apps.

NodeJs is based on JavaScript and can be used as a backend development language. Provides many system level apis, such as file manipulation, network programming, and so on. With event driven, asynchronous programming, mainly designed for background network services. React Native uses Node.js, the JavaScript runtime, to create JavaScript code.

In summary, React Native uses NodeJS for system processing and React for rendering.

Principle of building

In appdelegate.m, find

Application: didFinishLaunchingWithOptions:Copy the code

In this method, several things are done:

  • Defines the location of the JS code, which is a URL in the Dev environment, accessed through the Development Server; In production, it reads from disk, provided that the bundle file has been manually generated.
  • Create a RCTRootView object that inherits from UIView and handles the outermost layer of all uiViews.
  • Call the initWithBundleURL method of RCTRootView. In this method, a Bridge object is created. As the name implies, a bridge acts as a bridge between two ends, where the class that really works is the famous RCTBatchedBridge. The RCTBatchedBridge is the core of communication at initialization, and we focus on the start method. In the start method, a GCD thread is created that schedules the following key tasks through a serial queue.

RCTRootView is used to load the JavaScript application and render the final view. When the application starts running, RCTRootView will load the application from the following URL:

http://localhost:8081/index.ios.bundleCopy the code

Re-invoke the terminal window that you opened when you ran the App, and it opens a Packager and server to handle the above request. Open that URL in Safari; You’ll see the JavaScript code for this App. You can also find your code in the React Native framework. When your App is running, this code will be loaded and the JavaScriptCore framework will execute it. In the application, it’s going to load the functionality, and then build the native UIKit view. JavaScript applications run on emulators and use a native UI without any built-in browsers. The app uses React. CreateElement to build the app UI, and React converts it to its native environment.

When the UI is rendered, the Render method returns a view render tree and compares it to the current UIKit view. The output of this process, called reconciliation, is a simple list of updates that React applies to the current view. Only the parts that are actually changed are redrawn. ReactJS is unique to the concept of Virtual-DOM (document Object Model, a view tree of Web documents) and Reconciliation.

Component life cycle

The lifecycle of a component is divided into three states:

Mounting: True DOM Updating: The DOM is being re-rendered Unmounting: The DOM is removedCopy the code

React provides two handlers for each state. The will function is called before the state and the DID function is called after the state. There are five handlers for each state.

componentWillMount()
componentDidMount()
componentWillUpdate(object nextProps, object nextState)
componentDidUpdate(object prevProps, object prevState)
componentWillUnmount()Copy the code

React also provides two special state handlers.

ComponentWillReceiveProps (object nextProps) : loaded components received a new parameter called when shouldComponentUpdate (object nextProps, object nextState) : Called when the component decides whether to rerenderCopy the code

You can refer to the official documentation for detailed explanations of these methods.

Another point of concern is that the component’s style property cannot be set in such a way

style="opacity:{this.state.opacity};"Copy the code

But to write

style={{opacity: this.state.opacity}}Copy the code

This is because the React component style is an object, so the first major bracket indicates that this is JavaScript syntax and the second major bracket indicates the style object.

JS and Native interaction

Xcode starts and executes.. / node_modules/react – native packager/react – native – xcode. Sh file. The script reads the environment variables brought by Xcode, loads the NVM package to make the Node.js environment available, and executes the react-native cli command:

$NODE_BINARY "$REACT_NATIVE_DIR/local-cli/cli.js" bundle \\ --entry-file index.ios.js \\ --platform ios \\ --dev $DEV \\  --bundle-output "$DEST/main.jsbundle" \\ --assets-dest "$DEST"Copy the code

From here, index.ios.js and main.jsbundle are available.

Through.. /react-native/local-cli/cli.js run method goes to /bundle/bundle.js, and hence to /bundle/ buildbundle. js. From the js script, it can be seen that the following work is generally done:

  • Analyze the dependency relationship between modules from the entry file;
  • JS file transformation, such as JSX syntax transformation;
  • Combine the converted modules into one bundle.js.

React Native has made several improvements to its module analysis and compilation, which greatly improves the speed of packaging and ensures that users receive immediate responses while running liveReload.

After the application is started, the didFinishLaunchingWithOptions method is called, through the analysis of the above, we can see your own page is added to the application. JS engine. In the debug environment, the corresponding Executor is RCTWebSocketExecutor. It connects to Chrome through WebSocket and runs JS in Chrome. In a production environment, the corresponding Executor is RCTContextExecutor, which should be the javascriptcore of legend.

Native JS is invoked by sending a message to Chrome to trigger execution, or by executing javascript code directly through javascriptcore. Invoking Native at the JS end is generally by referring to the module name directly. JS saves (calling the module, calling the method, calling the parameter) in the queue. When Native calls JS, it returns the queue. Native handles the parameters in the queue and the same (module, method, parameter) is parsed out and dynamically invoked via NSInvocation; After the Native method is called, JS is actively called again. The JS side finds the corresponding JS side callback through callbackID and makes a call. Both ends save all exposed Native module information tables as the basis for communication.

JS does not actively transfer data to the OC. When calling the OC method, it adds ModuleID,MethodID and other data to a queue. When the OC calls any JS method, it returns the queue to the OC, and then the OC executes the method to be called in the queue. Native development executes code only when an event is triggered. In React Native, when an event occurs, OC calls the corresponding JS module method to handle it, and then executes the method that JS wants OC to execute. When no event occurs, OC does not execute any code.

In addition, if a Native module wants to be exposed to JS, it needs to explicitly call RCT_EXPORT_MODULE at declaration time. The macro defines the load method, which is automatically called to register the current class in the method. If a module wants to expose a specified method, it needs to declare it through the RCT_EXPORT_METHOD macro.

Conclusion: The whole startup process is that the JS side first packages the code as bundle. JS to the main function of the Native side, and the main function creates RCTRootView. Use GCD to scan exposed modules in RCTRootView, create a JS engine, and serialize the module information to JSON. At this point, the JS code is loaded, bundle. JS is executed in the JS engine, and the JSON object is deserialized and saved as a NativeModules object.




In the interaction between JS and Native, RCTBatchedBridge plays an important role in the communication between the two ends.

//RCTBatchedBridge.m - (void)start { dispatch_queue_t bridgeQueue = dispatch_queue_create("com.facebook.react.RCTBridgeQueue", DISPATCH_QUEUE_CONCURRENT); // Asynchronously load the packaged JS file, i.e. Main. jsbundle, directly if the package file is locally loaded. [self loadSource:^(NSError *error, NSData *source) {}]; // Synchronous initialization needs to be exposed to the js layer native module [self initModules]; // Initialize the JS Executor asynchronously, Is js engine dispatch_group_async (setupJSExecutorAndModuleConfig bridgeQueue, ^ {[weakSelf setUpExecutor]; }); / / asynchronous for each module configuration information dispatch_group_async (setupJSExecutorAndModuleConfig bridgeQueue, ^ {config = [weakSelf moduleConfig]; }); / / get the module configuration information, the information into the JS environment [self injectJSONConfiguration: config the onComplete: ^ (NSError * error) {}]. / / start executing main. Jsbundle [self executeSourceCode: sourceCode]; }Copy the code

BatchedBridge is also introduced in JS to bridge the native layer. BatchedBridge is an instance of MessageQueue, and it is the only instance globally. :

//BatchedBridge.js const MessageQueue = require('MessageQueue'); const BatchedBridge = new MessageQueue( __fbBatchedBridgeConfig.remoteModuleConfig, __fbBatchedBridgeConfig.localModulesConfig, ); DefineProperty (global, '__fbBatchedBridge', {value: BatchedBridge}); module.exports = BatchedBridge;Copy the code

FbBatchedBridgeConfig js variable is a global, fbBatchedBridgeConfig. RemoteModuleConfig is before us in the native export module configuration tables.

MessageQueue stores all information about INTERACTION between JS and native modules. _genModules method, _genModules will walk through all of the RemoteModules, creating each module based on its configuration information (how to generate configuration information is described below) and the module index ID .

React To optimize performance, when the interval between js calls is less than MIN_TIME_BETWEEN_FLUSHES_MS(5ms), the call information is cached in _queue and submitted to the native layer for execution next time.

Navigator component to NavigationExperimental component

Both Navigator and NavigatorIOS are stateful components that allow your APP to manage your navigation across multiple different scenes (screens). These two navigations manage a route stack, which allows us to use POP (), push(), and replace() to manage state. NavigatorIOS uses the iOS UINavigationController class, while Navigator is based on Javascript. Navigator works on both platforms, while NavigatorIOS only works on iOS. If you have multiple navigation components in an APP (Navigator and NavigatorIOS used together). It becomes very difficult to navigate the transition between the two.

NavigationExperimental implements navigation logic in a new way that allows any view to be a navigational view. It contains a pre-programmed component, NavigationAnimatedView, to manage animations between scenes. Each view inside it can have its own gestures and animations.

The React Native project has moved away from maintaining Navigator components in favor of NavigationExperimental components. NavigationExperimental improves the Following aspects of the Navigator component:

  • Unidirectional data flow, which uses reducers to operate the top-level state object, while in Navigator, when you are in the sub-navigation page, it is impossible to operate the state object when the app initially opens the page, unless method or function names are passed level by level through props. These methods or functions are then called in a child page to modify the top-level data.

  • To allow local and JS-BASED navigation views, navigation logic and routing must be separate from view logic.

  • Improved scene animation, gestures and navigation bar when switching

NavigationExperimental use: The implementation scheme can be refer to here.

Specific use can also be seen here.