-
探究react-native 源码的图片缓存问题
2020-08-29 15:07:15本篇文章主要介绍了探究react-native 源码的图片缓存问题,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 -
react-native 源码地址有吗?(github)上的,要最新版本的不要6以下的
2019-12-16 17:21:31react-native 源码地址有吗?(github)上的,要最新版本的不要6以下的 -
react-native源码分析系列一
2015-12-08 14:34:41react-native源码目前我看到过的最好的分析文章是qq空间分析的这篇。 http://zhuanlan.zhihu.com/magilu/20259704 不得不说大厂推出的分析确实牛逼,逻辑清晰。 不过由于博主自己也读过源码,也做过一些分析,...react-native源码目前我看到过的最好的分析文章是qq空间分析的这篇。
http://zhuanlan.zhihu.com/magilu/20259704
不得不说大厂推出的分析确实牛逼,逻辑清晰。
不过由于博主自己也读过源码,也做过一些分析,因此准备将这些分析整理一下放出来(这个系列会比较长。
react-native 官网https://github.com/facebook/react-native
这里不介绍怎么使用,有兴趣的可以参考我的个人项目https://github.com/xiaoshenke/React-Online-News
照例我们从demo开始分析,我看的demo是react-native/Examples/Movies工程。
以下rn代指react-native。
可以看到初始化代码只有两行。先看第一行代码,初始化构建ReactInstanceManager。ReactInstanceManagermReactInstanceManager = ReactInstanceManager.builder() //builder模式.setApplication(getApplication()).setBundleAssetName("MoviesApp.android.bundle") //bundleName貌似可以随便取.setJSMainModuleName("Examples/Movies/MoviesApp.android") //这里的名字必须是对应js文件入口的名字.addPackage(new MainReactPackage()) //注意名字 这里就是主要的rn包//官网有说明怎么加自定义包.setUseDeveloperSupport(true) //manifest中的DevSettingsActivity.setInitialLifecycleState(LifecycleState.RESUMED).build();public ReactInstanceManager build() {return new ReactInstanceManager(Assertions.assertNotNull(mApplication,"Application property has not been set with this builder"),mBundleAssetName,mJSMainModuleName,mPackages,mUseDeveloperSupport,mBridgeIdleDebugListener,Assertions.assertNotNull(mInitialLifecycleState, "Initial lifecycle state was not set"));}private ReactInstanceManager( //ReactInstanceManager构造函数Context applicationContext,@Nullable String bundleAssetName,@Nullable String jsMainModuleName,List<ReactPackage> packages,boolean useDeveloperSupport,@Nullable NotThreadSafeBridgeIdleDebugListener bridgeIdleDebugListener,LifecycleState initialLifecycleState) {initializeSoLoaderIfNecessary(applicationContext);mApplicationContext = applicationContext;mBundleAssetName = bundleAssetName; //这里传入的是“MoviesApp.android.bundle"mJSMainModuleName = jsMainModuleName; //这里传入的是“Examples/Movies/MoviesApp.android”mPackages = packages;mUseDeveloperSupport = useDeveloperSupport; //这里传入的是true// We need to instantiate DevSupportManager regardless to the useDeveloperSupport option,// although will prevent dev support manager from displaying any options or dialogs by// checking useDeveloperSupport option before calling setDevSupportEnabled on this manager// TODO(6803830): Don't instantiate devsupport manager when useDeveloperSupport is falsemDevSupportManager = new DevSupportManager( //调试用 这里不分析applicationContext,mDevInterface,mJSMainModuleName,useDeveloperSupport);mBridgeIdleDebugListener = bridgeIdleDebugListener;mLifecycleState = initialLifecycleState;}通过以上过程构造出了ReactInstanceManager然后是第二行代码。ReactRootView.startReactApplication我们看一下ReactRootView是干啥的。所以ReactRootView是React工程中的rootview,并且负责分发各种touch事件。public class ReactRootView extends SizeMonitoringFrameLayout implements RootViewpublic class SizeMonitoringFrameLayout extends FrameLayoutpublic interface RootView {void onChildStartedNativeGesture(MotionEvent androidEvent);}继续看真正的初始化入口startReactApplication函数。/*** Schedule rendering of the react component rendered by the JS application from the given JS* module (@{param moduleName}) using provided {@param reactInstanceManager} to attach to the* JS context of that manager. Extra parameter {@param launchOptions} can be used to pass initial* properties for the react component.*/public void startReactApplication(ReactInstanceManager reactInstanceManager,String moduleName,@Nullable Bundle launchOptions) { //这里的moduleName传入的是“MoviesApp”//如果你懂一点React.js的话 js代码大概长这样 module.exports=MoviesApp-->就是说这是一个可以被其他mudule调用的对象mReactInstanceManager = reactInstanceManager;mJSModuleName = moduleName;mLaunchOptions = launchOptions;if (mWasMeasured && mIsAttachedToWindow) {mReactInstanceManager.attachMeasuredRootView(this); //真正的入口mIsAttachedToInstance = true;getViewTreeObserver().addOnGlobalLayoutListener(mKeyboardListener);} else {mAttachScheduled = true;}}/*** Attach given {@param rootView} to a catalyst instance manager and start JS application using* JS module provided by {@link ReactRootView#getJSModuleName}. This view will then be tracked* by this manager and in case of catalyst instance restart it will be re-attached.*//* package */ void attachMeasuredRootView(ReactRootView rootView) {UiThreadUtil.assertOnUiThread();mAttachedRootViews.add(rootView);if (mCurrentReactContext == null) {initializeReactContext(); //生成重要对象ReactContext(很眼熟是不是~ 这个context继承自android的ContextWrapper//关于context 老罗的这篇文章http://blog.csdn.net/luoshengyang/article/details/8201936里//可以看到Activity是继承自ContextWrapper的} else {attachMeasuredRootViewToInstance(rootView, mCurrentReactContext.getCatalystInstance());}}initializeReactContext —> createReactContext //中间一系列调用略去/*** @return instance of {@link ReactContext} configured a {@link CatalystInstance} set*/private ReactApplicationContext createReactContext(JavaScriptExecutor jsExecutor,JSBundleLoader jsBundleLoader) {...} 重要函数 //后面一篇文章具体分析这个函数//剧透一下 大概就是干了生成一个context 注册了一堆双方共用的控件 服务 其实就是打通了js native代码交互的通道createReactContext后会调用attachMeasuredRootViewToInstanceprivate void attachMeasuredRootViewToInstance(ReactRootView rootView,CatalystInstance catalystInstance) {UiThreadUtil.assertOnUiThread();// Reset view content as it's going to be populated by the application content from JSrootView.removeAllViews();rootView.setId(View.NO_ID);UIManagerModule uiManagerModule = catalystInstance.getNativeModule(UIManagerModule.class); //注意名字 nativeModule//统一处理js java两边对应控件的manager// rn是用js封装了一套native的对应控件 比如native里的DrawerLayout js那边对应的是drawerLayoutAndroid//因此需要一个manager来进行协调int rootTag = uiManagerModule.addMeasuredRootView(rootView);//这里调用了native的addMeasuredRootView@Nullable Bundle launchOptions = rootView.getLaunchOptions();WritableMap initialProps = launchOptions != null? Arguments.fromBundle(launchOptions): Arguments.createMap();String jsAppModuleName = rootView.getJSModuleName(); //注意名字 jsModuleWritableNativeMap appParams = new WritableNativeMap();appParams.putDouble("rootTag", rootTag);appParams.putMap("initialProps", initialProps);catalystInstance.getJSModule(AppRegistry.class).runApplication(jsAppModuleName, appParams);//这里获取了js的一个模块 AppRegistry 并调用了js模块里的runApplication函数}ctrl f搜索runApplication。可以看到对应的js文件及runApplication这个接口。AppRegistry.js文件。好了,第一篇文章先到这里。总结一下,这篇文章分析了react-native初始化的过程(两行代码。第一行代码,构造出一个reactInstanceManager类(这个类就是一个调度类。第二行代码,ReactRootView.startApplication(这里是初始化入口,包括生成重要的ReactContext 以及后面的打通js java native通信等等。
-
5000字的React-native源码解析
2020-06-22 08:00:00写在开头近期公众号主攻下React-native,顺便我也复习下React-native,后续写作计划应该是主攻Node.js和跨平台方向、架构、Debug为主如果你感兴趣,建议关注下公...写在开头
近期公众号主攻下
React-native
,顺便我也复习下React-native,后续写作计划应该是主攻Node.js和跨平台方向、架构、Debug
为主如果你感兴趣,建议关注下公众号,系统的学习下,推荐阅读之前我的的年度原创文章集合:
https://mp.weixin.qq.com/s/RsvI5AFzbp3rm6sOlTmiYQ
正式开始
环境准备:Node、Watchman、Xcode 和 CocoaPods & XCode ,
稳定的代理工具
(如果没有稳定的代理工具,基本上可以考虑放弃了)生成项目
npx react-native init App cd App yarn cd cd ios pod install (注意不要+sudo,此处必须全局开启代理,否则下载会失败) cd .. yarn ios
如果yarn ios后无法看到Simulator有APP,使用xCode找到这个项目的ios目录的.xcworkspace
❝
注意 0.60 版本之后的主项目文件是.xcworkspace,不是.xcodeproj。
❞然后用xCode打开build,成功后模拟器就会出现APP,打开即可进入
⚠️:一定不要升级xCode高版本,跟我的版本保持一致最好,因为高版本xCode的voip唤醒激活会出现电话界面
如果你的环境是windows或者安卓,请参考官网
正式开始
启动后,发现APP这样
我们打开主入口的index.js文件
/** * @format */ import {AppRegistry} from 'react-native'; import App from './App'; import {name as appName} from './app.json'; AppRegistry.registerComponent(appName, () => App);
默认使用AppRegistry.registerComponent帮我们注册了一个组件(今天不对原理做过多讲解,有兴趣的可以自己搭建一个React-native脚手架,你会对整套运行原理、流程有一个真正的了解)
接下来看APP组件
import React from 'react'; import { SafeAreaView, StyleSheet, ScrollView, View, Text, StatusBar, } from 'react-native'; import { Header, LearnMoreLinks, Colors, DebugInstructions, ReloadInstructions, } from 'react-native/Libraries/NewAppScreen'; const App: () => React$Node = () => { return ( <> <StatusBar barStyle="dark-content" /> <SafeAreaView> <ScrollView contentInsetAdjustmentBehavior="automatic" style={styles.scrollView}> <Header /> {global.HermesInternal == null ? null : ( <View style={styles.engine}> <Text style={styles.footer}>Engine: Hermes</Text> </View> )} <View style={styles.body}> <View style={styles.pContainer}> <Text style={styles.pTitle}>Step One</Text> <Text style={styles.pDescription}> Edit <Text style={styles.highlight}>App.js</Text> to change this screen and then come back to see your edits. </Text> </View> <View style={styles.pContainer}> <Text style={styles.pTitle}>See Your Changes</Text> <Text style={styles.pDescription}> <ReloadInstructions /> </Text> </View> <View style={styles.pContainer}> <Text style={styles.pTitle}>Debug</Text> <Text style={styles.pDescription}> <DebugInstructions /> </Text> </View> <View style={styles.pContainer}> <Text style={styles.pTitle}>Learn More</Text> <Text style={styles.pDescription}> Read the docs to discover what to do next: </Text> </View> <LearnMoreLinks /> </View> </ScrollView> </SafeAreaView> </> ); }; const styles = StyleSheet.create({ ... }); export default App;
我们今天只看react-native这个库,默认导出的内容.
即下面这段代码
import { SafeAreaView, StyleSheet, ScrollView, View, Text, StatusBar, } from 'react-native';
打开react-native源码
'use strict'; import typeof Button from './Libraries/Components/Button'; .... export type HostComponent<T> = _HostComponentInternal<T>; const invariant = require('invariant'); const warnOnce = require('./Libraries/Utilities/warnOnce'); module.exports = { // Components get Button(): Button { return require('./Libraries/Components/Button'); }, ... }; if (__DEV__) { // $FlowFixMe This is intentional: Flow will error when attempting to access ART. Object.defineProperty(module.exports, 'ART', { configurable: true, get() { invariant( false, 'ART has been removed from React Native. ' + "It can now be installed and imported from '@react-native-community/art' instead of 'react-native'. " + 'See https://github.com/react-native-community/art', ); }, }); // $FlowFixMe This is intentional: Flow will error when attempting to access ListView. Object.defineProperty(module.exports, 'ListView', { configurable: true, get() { invariant( false, 'ListView has been removed from React Native. ' + 'See https://fb.me/nolistview for more information or use ' + '`deprecated-react-native-listview`.', ); }, }); // $FlowFixMe This is intentional: Flow will error when attempting to access SwipeableListView. Object.defineProperty(module.exports, 'SwipeableListView', { configurable: true, get() { invariant( false, 'SwipeableListView has been removed from React Native. ' + 'See https://fb.me/nolistview for more information or use ' + '`deprecated-react-native-swipeable-listview`.', ); }, }); // $FlowFixMe This is intentional: Flow will error when attempting to access WebView. Object.defineProperty(module.exports, 'WebView', { configurable: true, get() { invariant( false, 'WebView has been removed from React Native. ' + "It can now be installed and imported from 'react-native-webview' instead of 'react-native'. " + 'See https://github.com/react-native-community/react-native-webview', ); }, }); // $FlowFixMe This is intentional: Flow will error when attempting to access NetInfo. Object.defineProperty(module.exports, 'NetInfo', { configurable: true, get() { invariant( false, 'NetInfo has been removed from React Native. ' + "It can now be installed and imported from '@react-native-community/netinfo' instead of 'react-native'. " + 'See https://github.com/react-native-community/react-native-netinfo', ); }, }); // $FlowFixMe This is intentional: Flow will error when attempting to access CameraRoll. Object.defineProperty(module.exports, 'CameraRoll', { configurable: true, get() { invariant( false, 'CameraRoll has been removed from React Native. ' + "It can now be installed and imported from '@react-native-community/cameraroll' instead of 'react-native'. " + 'See https://github.com/react-native-community/react-native-cameraroll', ); }, }); // $FlowFixMe This is intentional: Flow will error when attempting to access ImageStore. Object.defineProperty(module.exports, 'ImageStore', { configurable: true, get() { invariant( false, 'ImageStore has been removed from React Native. ' + 'To get a base64-encoded string from a local image use either of the following third-party libraries:' + "* expo-file-system: `readAsStringAsync(filepath, 'base64')`" + "* react-native-fs: `readFile(filepath, 'base64')`", ); }, }); // $FlowFixMe This is intentional: Flow will error when attempting to access ImageEditor. Object.defineProperty(module.exports, 'ImageEditor', { configurable: true, get() { invariant( false, 'ImageEditor has been removed from React Native. ' + "It can now be installed and imported from '@react-native-community/image-editor' instead of 'react-native'. " + 'See https://github.com/react-native-community/react-native-image-editor', ); }, }); // $FlowFixMe This is intentional: Flow will error when attempting to access TimePickerAndroid. Object.defineProperty(module.exports, 'TimePickerAndroid', { configurable: true, get() { invariant( false, 'TimePickerAndroid has been removed from React Native. ' + "It can now be installed and imported from '@react-native-community/datetimepicker' instead of 'react-native'. " + 'See https://github.com/react-native-community/datetimepicker', ); }, }); // $FlowFixMe This is intentional: Flow will error when attempting to access ViewPagerAndroid. Object.defineProperty(module.exports, 'ViewPagerAndroid', { configurable: true, get() { invariant( false, 'ViewPagerAndroid has been removed from React Native. ' + "It can now be installed and imported from '@react-native-community/viewpager' instead of 'react-native'. " + 'See https://github.com/react-native-community/react-native-viewpager', ); }, }); }
我删了一些倒入和get定义,方便阅读
这个源码文件大概有650行,module.export暴露出来了很多东西,但是,区分多种
一种是Components组件
一种是API
一种是Plugins
一种是Prop Types
还有一种是最后的DEV环境下,
逐个攻破
首先是组件
其次是API
然后是Plugins
然后是Prop types
最后是DEV环境下的对旧版本的部分API使用方式警告
可以看到入口文件中的一些API
例如
get AppRegistry(): AppRegistry { return require('./Libraries/ReactNative/AppRegistry'); },
图片
get Image(): Image { return require('./Libraries/Image/Image'); },
拿Image组件源码示例
找到
./Libraries/Image/Image
源码
脚手架应该根据是react-native run ios 还是 安卓,选择加载对应js,我们找到Image.ios.js文件,只有200行,今天重点主攻下
默认暴露
module.exports = ((Image: any): React.AbstractComponent< ImagePropsType, React.ElementRef<typeof RCTImageView>, > & ImageComponentStatics);
Image对象
Image组件真正展示的
return ( <RCTImageView {...props} ref={forwardedRef} style={style} resizeMode={resizeMode} tintColor={tintColor} source={sources} /> );
找到
RCTImageView
,ImageViewNativeComponent.js
这个文件
let ImageViewNativeComponent; if (global.RN$Bridgeless) { ImageViewNativeComponent = codegenNativeComponent<NativeProps>( 'RCTImageView', ); } else { ImageViewNativeComponent = requireNativeComponent<NativeProps>( 'RCTImageView', ); } module.exports = (ImageViewNativeComponent: HostComponent<NativeProps>);
真正展示的是
ImageViewNativeComponent
,关于上面这段源码我查阅了一些的外文资料和其他源码,最终发现了一个注释
const NativeModules = require('../BatchedBridge/NativeModules'); const turboModuleProxy = global.__turboModuleProxy; export function get < T: TurboModule > (name: string): ? T { if (!global.RN$Bridgeless) { // Backward compatibility layer during migration. const legacyModule = NativeModules[name]; if (legacyModule != null) { return ((legacyModule: any): T); } } if (turboModuleProxy != null) { const module: ? T = turboModuleProxy(name); return module; } return null; } export function getEnforcing < T: TurboModule > (name: string): T { const module = get(name); return module; }
即
Backward compatibility layer during migration.
,即迁移过程中向后兼容,即兼容性处理这个
codegenNativeComponent
就是图片展示最终的一环,我们去看看是什么
忽略类型等其它空值警告判断,直入主题
let componentNameInUse = options && options.paperComponentName ? options.paperComponentName : componentName; if (options != null && options.paperComponentNameDeprecated != null) { if (UIManager.getViewManagerConfig(componentName)) { componentNameInUse = componentName; } else if ( options.paperComponentNameDeprecated != null && UIManager.getViewManagerConfig(options.paperComponentNameDeprecated) ) { componentNameInUse = options.paperComponentNameDeprecated; } else { throw new Error( `Failed to find native component for either ${componentName} or ${options.paperComponentNameDeprecated || '(unknown)'}`, ); } } // If this function is run at runtime then that means the view configs were not // generated with the view config babel plugin, so we need to require the native component. // // This will be useful during migration, but eventually this will error. return (requireNativeComponent<Props>( componentNameInUse, ): HostComponent<Props>);
还是 要先看
UIManager.getViewManagerConfig
'use strict'; import type {Spec} from './NativeUIManager'; interface UIManagerJSInterface extends Spec { +getViewManagerConfig: (viewManagerName: string) => Object; +createView: ( reactTag: ?number, viewName: string, rootTag: number, props: Object, ) => void; +updateView: (reactTag: number, viewName: string, props: Object) => void; +manageChildren: ( containerTag: ?number, moveFromIndices: Array<number>, moveToIndices: Array<number>, addChildReactTags: Array<number>, addAtIndices: Array<number>, removeAtIndices: Array<number>, ) => void; } const UIManager: UIManagerJSInterface = global.RN$Bridgeless === true ? require('./DummyUIManager') // No UIManager in bridgeless mode : require('./PaperUIManager'); module.exports = UIManager;
进入
PaperUIManager
找到getViewManagerConfig
getViewManagerConfig: function(viewManagerName: string): any { if ( viewManagerConfigs[viewManagerName] === undefined && NativeUIManager.getConstantsForViewManager ) { try { viewManagerConfigs[ viewManagerName ] = NativeUIManager.getConstantsForViewManager(viewManagerName); } catch (e) { viewManagerConfigs[viewManagerName] = null; } } const config = viewManagerConfigs[viewManagerName]; if (config) { return config; } // If we're in the Chrome Debugger, let's not even try calling the sync // method. if (!global.nativeCallSyncHook) { return config; } if ( NativeUIManager.lazilyLoadView && !triedLoadingConfig.has(viewManagerName) ) { const result = NativeUIManager.lazilyLoadView(viewManagerName); triedLoadingConfig.add(viewManagerName); if (result.viewConfig) { getConstants()[viewManagerName] = result.viewConfig; lazifyViewManagerConfig(viewManagerName); } } return viewManagerConfigs[viewManagerName]; },
viewManagerConfigs
初始化是一个空对象,key-value形式存储、管理这些原生视图配置我突然发现我错了路线,因为React-native虽然是用js写代码,不过最终都是转换成原生控件,回到主题的第一个代码底部
return (requireNativeComponent<Props>( componentNameInUse, ): HostComponent<Props>);
最最关键的是:
requireNativeComponent
,根据componentName去加载原生组件,找到源码
'use strict'; const createReactNativeComponentClass = require('../Renderer/shims/createReactNativeComponentClass'); const getNativeComponentAttributes = require('./getNativeComponentAttributes'); import type {HostComponent} from '../Renderer/shims/ReactNativeTypes'; const requireNativeComponent = <T>(uiViewClassName: string): HostComponent<T> => ((createReactNativeComponentClass(uiViewClassName, () => getNativeComponentAttributes(uiViewClassName), ): any): HostComponent<T>); module.exports = requireNativeComponent;
❝
最重要的加载原生组件的代码找到了
❞((createReactNativeComponentClass(uiViewClassName, () => getNativeComponentAttributes(uiViewClassName), ): any): HostComponent<T>)
解析`createReactNativeComponentClass
给
createReactNativeComponentClass
传入uiViewClassName
即组件name,传入回调函数,返回getNativeComponentAttributes(uiViewClassName)
找到源码
createReactNativeComponentClass
/** * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * @format * @flow strict-local */ 'use strict'; import {ReactNativeViewConfigRegistry} from 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface'; import type {ViewConfigGetter} from './ReactNativeTypes'; const {register} = ReactNativeViewConfigRegistry; /** * Creates a renderable ReactNative host component. * Use this method for view configs that are loaded from UIManager. * Use createReactNativeComponentClass() for view configs defined within JavaScript. * * @param {string} config iOS View configuration. * @private */ const createReactNativeComponentClass = function( name: string, callback: ViewConfigGetter, ): string { return register(name, callback); }; module.exports = createReactNativeComponentClass;
跟我预想一样,向register函数传入name和cb,注册成功后触发callback(getNativeComponentAttributes)
找到
ReactNativePrivateInterface.js
里面的ReactNativeViewConfigRegistry
get ReactNativeViewConfigRegistry(): ReactNativeViewConfigRegistry { return require('../Renderer/shims/ReactNativeViewConfigRegistry'); },
再找到register方法
exports.register = function(name: string, callback: ViewConfigGetter): string { invariant( !viewConfigCallbacks.has(name), 'Tried to register two views with the same name %s', name, ); invariant( typeof callback === 'function', 'View config getter callback for component `%s` must be a function (received `%s`)', name, callback === null ? 'null' : typeof callback, ); viewConfigCallbacks.set(name, callback); return name; };
重点:viewConfigCallbacks.set(name, callback);viewConfigCallbacks是一个Map类型(ES6),key-value数据结构,怎么理解这段代码,看注释:
按名称注册本机视图/组件。 提供了一个回调函数来从UIManager加载视图配置。 回调被延迟直到视图被实际呈现。
至此,加载原生组件逻辑配合之前的UImanager,getViewManagerConfig那块源码就解析完了。
这是我们传入的cb(回调函数),获取原生组件属性
function getNativeComponentAttributes(uiViewClassName: string): any { const viewConfig = UIManager.getViewManagerConfig(uiViewClassName); invariant( viewConfig != null && viewConfig.NativeProps != null, 'requireNativeComponent: "%s" was not found in the UIManager.', uiViewClassName, ); // TODO: This seems like a whole lot of runtime initialization for every // native component that can be either avoided or simplified. let {baseModuleName, bubblingEventTypes, directEventTypes} = viewConfig; let nativeProps = viewConfig.NativeProps; while (baseModuleName) { const baseModule = UIManager.getViewManagerConfig(baseModuleName); if (!baseModule) { warning(false, 'Base module "%s" does not exist', baseModuleName); baseModuleName = null; } else { bubblingEventTypes = { ...baseModule.bubblingEventTypes, ...bubblingEventTypes, }; directEventTypes = { ...baseModule.directEventTypes, ...directEventTypes, }; nativeProps = { ...baseModule.NativeProps, ...nativeProps, }; baseModuleName = baseModule.baseModuleName; } } const validAttributes = {}; for (const key in nativeProps) { const typeName = nativeProps[key]; const diff = getDifferForType(typeName); const process = getProcessorForType(typeName); validAttributes[key] = diff == null && process == null ? true : {diff, process}; } // Unfortunately, the current setup declares style properties as top-level // props. This makes it so we allow style properties in the `style` prop. // TODO: Move style properties into a `style` prop and disallow them as // top-level props on the native side. validAttributes.style = ReactNativeStyleAttributes; Object.assign(viewConfig, { uiViewClassName, validAttributes, bubblingEventTypes, directEventTypes, }); if (!hasAttachedDefaultEventTypes) { attachDefaultEventTypes(viewConfig); hasAttachedDefaultEventTypes = true; } return viewConfig; }
至此,一个完整的React-native组件解析从加载、注册、展现整个过程就解析完了。
写在最后
本文gitHub源码仓库:
https://github.com/JinJieTan/chunchao
,记得给个star
哦我是Peter,架构设计过20万人端到端加密超级群功能的桌面IM软件,现在是一名前端架构师。
如果你对性能优化有很深的研究,可以跟我一起交流交流,今天这里写得比较浅,但是大部分人都够用,之前问我的朋友,我让它写了一个定时器定时消费队列,最后也能用。哈哈
另外欢迎收藏我的资料网站:前端生活社区:
https://qianduan.life
,感觉对你有帮助,可以右下角点个在看
,关注一波公众号:[前端巅峰
]
-
React Native releases are discussed in the React Native Community, @react-native-community/react-native-releases. How to Contribute The main purpose of this repository is to continue evolving React ...
-
react-native-maps-demo:react-native-maps-demo-源码
2021-02-17 09:00:23react-native-maps-demo:react-native-maps-demo -
curso-react-native:Curso React-native-Mateus Fraga-源码
2021-02-13 09:54:51curso-react-native:Curso React-native-Mateus Fraga -
React-Native-Spotify-Lite:使用react-native的Spotify克隆-源码
2021-02-12 10:17:35React-Native-Spotify-Lite:使用react-native的Spotify克隆 -
react-native-cached-image:react-native的CachedImage组件-源码
2021-02-05 11:10:48这个软件包的灵感来自惊人的但是增加了一些功能,当我们尝试在我们的react-native应用程序中缓存图像时,我们会缺少这些功能。 安装 npm install react-native-cached-image --save - or - yarn add react-native-... -
react-native-training:我的react-native训练文件-源码
2021-02-12 21:54:57react-native-training:我的react-native训练文件 -
react-native-collapsing-toolbar:Android CollapsingToolbarLayout的react-native包装器-源码
2021-02-05 11:15:53react-native-collapsing-工具栏 react-native包装器,易于与Animated.Event和FlatList集成。 入门 确保同时安装react-native-collapsing-toolbar和react-native-nested-scroll-view 。 $ npm install react-native... -
react-native-tabbar-interaction:用于React-Native的Tabbar组件-源码
2021-02-05 11:16:55React本机Tabbar交互 使用React Native进行的滑动插入式FAB的精美Tabbar交互。 在Béhance上查看( ) 在Dribbble上查看( ) ...import TabBar from "@mindinventory/react-native-tab-bar-interacti -
react-native-ART-doc:react react-native ART模块的非官方文档-源码
2021-02-05 09:44:56react-native-ART-doc:react react-native ART模块的非官方文档 -
react-native-zeroconf:使用react-native发现Zeroconf服务-源码
2021-02-05 11:04:33react-native-zeroconf React-native的基本Zeroconf实现 使用Zeroconf实现(例如Avahi,Bonjour或NSD)来宣传自己的运行服务。 安装 yarn add react-native-zeroconf # for react-native < 0> = 7上可用。 -
React-Native-源码
2021-03-04 09:57:40React-Native -
react-native-onboarding-swiper:React React-Native应用程序的新手入门-源码
2021-02-05 11:14:22但是对于React-Native,只有一个组件是a)易于设置和b)高度可定制的: react-native-onboarding-swiper 。 您的新用户不应陷入困境。 首先给他们一个愉快,愉快的介绍,然后让他们探索您的真棒应用程序。 使一切... -
react-native-material-kit:将材料设计引入React Native-源码
2021-02-03 07:58:56react-native-material-kit> = 0.4.0仅支持react-native> = 0.40.0 react-native-material-kit <0> = 0.29 npm install -S react-native-material-kit react-native link react-native-material-kit 手动地 将... -
react-native-maps-directions:“ react-native-maps”的Directions组件-源码
2021-02-05 11:03:35react-native-maps-directions Directions组件–在两个坐标之间绘制路线,由Google Maps Directions API提供支持 安装 使用以下任一方法将react-native-maps-directions安装为依赖项 npm install react-native-... -
react-native-qrcode-svg:基于react-native-svg和node-qrcode的React Native QR码生成器-源码
2021-02-05 11:13:03react-native-qrcode-svg 基于react-native-svg和javascript-qrcode的React Native QR码生成器。 讨论: : 产品特点 轻松渲染QR码图像 (可选)嵌入徽标 安卓 的iOS 安装 安装依赖包 yarn add react-native-svg ... -
react-native-hiapp:用react-native编写的HiApp-源码
2021-02-05 11:07:34用react-native编写。 预告片 镜子: 要求 0.61.1 (遵循iOS和Android指南) 建立 提供了一个开发环境。 您可以调试代码,从命令选项板快速运行react-native命令,并使用IntelliSense浏览React Native API的对象,... -
react-native-dva-starter:由dva和react-navigation驱动的React Native入门-源码
2021-02-05 11:10:00react-native-dva-starter 由和驱动的React Native启动器 开始 npm install dva-native-cli -g dvanative git app cd app react-native run-ios # or react-native run-android 非常感谢@ xuan45提供的cli工具 ,... -
sentry-react-native:官方Sentry SDK,用于react-native-源码
2021-01-31 06:52:47react-native link @sentry/react-native # OR, if self hosting SENTRY_WIZARD_URL=http://sentry.acme.com/ react-native link @sentry/react-native 如何使用它: import * as Sentry from "@sentry/react-... -
react-native-css:使用CSS样式化React-Native组件-源码
2021-02-19 18:44:59react-native-css React-native-css将有效CSS转换为CSS的Facebook子集。 Babel插件 很棒的@ danilosterrapid7为React-native-css创建了一个babel插件: 版本2 随着版本2的到来,新的变化: 删除sass / scss支持,... -
Quizex-React-Native-源码
2021-02-17 21:36:47Quizex-React-Native -
Prueba-React-Native-源码
2021-02-17 07:35:52Prueba-React-Native -
react-native-keyboard-spacer:即插即用react-native-keyboard spacer view-源码
2021-02-03 17:09:26react-native-keyboard-spacer 即插即用iOS react-native键盘间隔视图。 快速开始 安装视图: npm install --save react-native-keyboard-spacer 用法示例 当键盘出现或消失时,视图将自动执行布局动画。 import ... -
gamezone-React-Native-源码
2021-02-12 18:21:27gamezone-React-Native