1import React from 'react'; 2import { findNodeHandle, NativeModules, requireNativeComponent } from 'react-native'; 3import { requireNativeModule } from './requireNativeModule'; 4/** 5 * A map that caches registered native components. 6 */ 7const nativeComponentsCache = new Map(); 8/** 9 * Requires a React Native component from cache if possible. This prevents 10 * "Tried to register two views with the same name" errors on fast refresh, but 11 * also when there are multiple versions of the same package with native component. 12 */ 13function requireCachedNativeComponent(viewName) { 14 const cachedNativeComponent = nativeComponentsCache.get(viewName); 15 if (!cachedNativeComponent) { 16 const nativeComponent = requireNativeComponent(viewName); 17 nativeComponentsCache.set(viewName, nativeComponent); 18 return nativeComponent; 19 } 20 return cachedNativeComponent; 21} 22/** 23 * A drop-in replacement for `requireNativeComponent`. 24 */ 25export function requireNativeViewManager(viewName) { 26 const { viewManagersMetadata } = NativeModules.NativeUnimoduleProxy; 27 const viewManagerConfig = viewManagersMetadata?.[viewName]; 28 if (__DEV__ && !viewManagerConfig) { 29 const exportedViewManagerNames = Object.keys(viewManagersMetadata).join(', '); 30 console.warn(`The native view manager required by name (${viewName}) from NativeViewManagerAdapter isn't exported by expo-modules-core. Views of this type may not render correctly. Exported view managers: [${exportedViewManagerNames}].`); 31 } 32 // Set up the React Native native component, which is an adapter to the universal module's view 33 // manager 34 const reactNativeViewName = `ViewManagerAdapter_${viewName}`; 35 const ReactNativeComponent = requireCachedNativeComponent(reactNativeViewName); 36 const proxiedPropsNames = viewManagerConfig?.propsNames ?? []; 37 class NativeComponent extends React.PureComponent { 38 static displayName = viewName; 39 // This will be accessed from native when the prototype functions are called, 40 // in order to find the associated native view. 41 nativeTag = null; 42 componentDidMount() { 43 this.nativeTag = findNodeHandle(this); 44 } 45 render() { 46 const nativeProps = omit(this.props, proxiedPropsNames); 47 const proxiedProps = pick(this.props, proxiedPropsNames); 48 return React.createElement(ReactNativeComponent, { ...nativeProps, proxiedProperties: proxiedProps }); 49 } 50 } 51 try { 52 const nativeModule = requireNativeModule(viewName); 53 const nativeViewPrototype = nativeModule.ViewPrototype; 54 if (nativeViewPrototype) { 55 // Assign native view functions to the component prototype so they can be accessed from the ref. 56 Object.assign(NativeComponent.prototype, nativeViewPrototype); 57 } 58 } 59 catch { 60 // `requireNativeModule` may throw an error when the native module cannot be found. 61 // In some tests we don't mock the entire modules, but we do want to mock native views. For now, 62 // until we still have to support the legacy modules proxy and don't have better ways to mock, 63 // let's just gracefully skip assigning the prototype functions. 64 // See: https://github.com/expo/expo/blob/main/packages/expo-modules-core/src/__tests__/NativeViewManagerAdapter-test.native.tsx 65 } 66 return NativeComponent; 67} 68function omit(props, propNames) { 69 const copied = { ...props }; 70 for (const propName of propNames) { 71 delete copied[propName]; 72 } 73 return copied; 74} 75function pick(props, propNames) { 76 return propNames.reduce((prev, curr) => { 77 if (curr in props) { 78 prev[curr] = props[curr]; 79 } 80 return prev; 81 }, {}); 82} 83//# sourceMappingURL=NativeViewManagerAdapter.native.js.map