1import React from 'react'; 2import { NativeModules, requireNativeComponent } from 'react-native'; 3 4// To make the transition from React Native's `requireNativeComponent` to Expo's 5// `requireNativeViewManager` as easy as possible, `requireNativeViewManager` is a drop-in 6// replacement for `requireNativeComponent`. 7// 8// For each view manager, we create a wrapper component that accepts all of the props available to 9// the author of the universal module. This wrapper component splits the props into two sets: props 10// passed to React Native's View (ex: style, testID) and custom view props, which are passed to the 11// adapter view component in a prop called `proxiedProperties`. 12 13type NativeExpoComponentProps = { 14 proxiedProperties: object; 15}; 16 17/** 18 * A drop-in replacement for `requireNativeComponent`. 19 */ 20export function requireNativeViewManager<P = any>(viewName: string): React.ComponentType<P> { 21 const { viewManagersMetadata } = NativeModules.NativeUnimoduleProxy; 22 const viewManagerConfig = viewManagersMetadata?.[viewName]; 23 24 if (__DEV__ && !viewManagerConfig) { 25 const exportedViewManagerNames = Object.keys(viewManagersMetadata).join(', '); 26 console.warn( 27 `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}].` 28 ); 29 } 30 31 // Set up the React Native native component, which is an adapter to the universal module's view 32 // manager 33 const reactNativeViewName = `ViewManagerAdapter_${viewName}`; 34 const ReactNativeComponent = 35 requireNativeComponent<NativeExpoComponentProps>(reactNativeViewName); 36 const proxiedPropsNames = viewManagerConfig?.propsNames ?? []; 37 38 // Define a component for universal-module authors to access their native view manager 39 function NativeComponentAdapter(props, ref) { 40 const nativeProps = omit(props, proxiedPropsNames); 41 const proxiedProps = pick(props, proxiedPropsNames); 42 return <ReactNativeComponent {...nativeProps} proxiedProperties={proxiedProps} ref={ref} />; 43 } 44 NativeComponentAdapter.displayName = `Adapter<${viewName}>`; 45 return React.forwardRef(NativeComponentAdapter); 46} 47 48function omit(props: Record<string, any>, propNames: string[]) { 49 const copied = { ...props }; 50 for (const propName of propNames) { 51 delete copied[propName]; 52 } 53 return copied; 54} 55 56function pick(props: Record<string, any>, propNames: string[]) { 57 return propNames.reduce((prev, curr) => { 58 if (curr in props) { 59 prev[curr] = props[curr]; 60 } 61 return prev; 62 }, {}); 63} 64