RN: Create `NativeComponentRegistry`
Summary: Creates `NativeComponentRegistry` which makes native component initialization more declarative and configurable through an optionally configurable provider. The next diff converts `ScrollView` to use this new abstraction as a demonstration. The plan would be to use this to replace all current manual call sites of `registerGeneratedViewConfig`, and then the ones generated via the Babel plugin. Migrating to this will not change any production behavior, but it will enable verification of `ViewConfig` in development. Changelog: [Internal] Reviewed By: JoshuaGross Differential Revision: D25084468 fbshipit-source-id: 9c758ddc279bf937a401a868a066907a94098f37
This commit is contained in:
Родитель
c797fcf5aa
Коммит
6a547c6c57
|
@ -0,0 +1,78 @@
|
|||
/**
|
||||
* 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.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import {createViewConfig} from './ViewConfig';
|
||||
import type {
|
||||
HostComponent,
|
||||
PartialViewConfig,
|
||||
} from '../Renderer/shims/ReactNativeTypes';
|
||||
import ReactNativeViewConfigRegistry from '../Renderer/shims/ReactNativeViewConfigRegistry';
|
||||
import getNativeComponentAttributes from '../ReactNative/getNativeComponentAttributes';
|
||||
import verifyComponentAttributeEquivalence from '../Utilities/verifyComponentAttributeEquivalence';
|
||||
import invariant from 'invariant';
|
||||
|
||||
let getRuntimeConfig;
|
||||
|
||||
/**
|
||||
* Configures a function that is called to determine whether a given component
|
||||
* should be registered using reflection of the native component at runtime.
|
||||
*/
|
||||
export function setRuntimeConfigProvider(
|
||||
runtimeConfigProvider: (name: string) => {native: boolean, verify: boolean},
|
||||
): void {
|
||||
invariant(
|
||||
getRuntimeConfig == null,
|
||||
'NativeComponentRegistry.setRuntimeConfigProvider() called more than once.',
|
||||
);
|
||||
getRuntimeConfig = runtimeConfigProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a `NativeComponent` that can be rendered by React Native.
|
||||
*
|
||||
* The supplied `viewConfigProvider` may or may not be invoked and utilized,
|
||||
* depending on how `setRuntimeConfigProvider` is configured.
|
||||
*/
|
||||
export function get<Config>(
|
||||
name: string,
|
||||
viewConfigProvider: () => PartialViewConfig,
|
||||
): HostComponent<Config> {
|
||||
ReactNativeViewConfigRegistry.register(name, () => {
|
||||
const {native, verify} = getRuntimeConfig?.(name) ?? {
|
||||
native: true,
|
||||
verify: false,
|
||||
};
|
||||
|
||||
const viewConfig = native
|
||||
? getNativeComponentAttributes(name)
|
||||
: createViewConfig(viewConfigProvider());
|
||||
|
||||
if (verify) {
|
||||
if (native) {
|
||||
verifyComponentAttributeEquivalence(
|
||||
viewConfig,
|
||||
createViewConfig(viewConfigProvider()),
|
||||
);
|
||||
} else {
|
||||
verifyComponentAttributeEquivalence(
|
||||
getNativeComponentAttributes(name),
|
||||
viewConfig,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return viewConfig;
|
||||
});
|
||||
|
||||
// $FlowFixMe[incompatible-return] `NativeComponent` is actually string!
|
||||
return name;
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/**
|
||||
* 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
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const React = require('react');
|
||||
|
||||
module.exports = viewName => {
|
||||
const Component = class extends React.Component {
|
||||
render() {
|
||||
return React.createElement(viewName, this.props, this.props.children);
|
||||
}
|
||||
|
||||
// The methods that exist on host components
|
||||
blur = jest.fn();
|
||||
focus = jest.fn();
|
||||
measure = jest.fn();
|
||||
measureInWindow = jest.fn();
|
||||
measureLayout = jest.fn();
|
||||
setNativeProps = jest.fn();
|
||||
};
|
||||
|
||||
if (viewName === 'RCTView') {
|
||||
Component.displayName = 'View';
|
||||
} else {
|
||||
Component.displayName = viewName;
|
||||
}
|
||||
|
||||
return Component;
|
||||
};
|
|
@ -325,33 +325,17 @@ jest
|
|||
}),
|
||||
},
|
||||
}))
|
||||
.mock('../Libraries/ReactNative/requireNativeComponent', () => {
|
||||
const React = require('react');
|
||||
|
||||
return viewName => {
|
||||
const Component = class extends React.Component {
|
||||
render() {
|
||||
return React.createElement(viewName, this.props, this.props.children);
|
||||
}
|
||||
|
||||
// The methods that exist on host components
|
||||
blur = jest.fn();
|
||||
focus = jest.fn();
|
||||
measure = jest.fn();
|
||||
measureInWindow = jest.fn();
|
||||
measureLayout = jest.fn();
|
||||
setNativeProps = jest.fn();
|
||||
};
|
||||
|
||||
if (viewName === 'RCTView') {
|
||||
Component.displayName = 'View';
|
||||
} else {
|
||||
Component.displayName = viewName;
|
||||
}
|
||||
|
||||
return Component;
|
||||
.mock('../Libraries/NativeComponent/NativeComponentRegistry', () => {
|
||||
return {
|
||||
get: jest.fn((name, viewConfigProvider) => {
|
||||
return jest.requireActual('./mockNativeComponent')(name);
|
||||
}),
|
||||
setRuntimeConfigProvider: jest.fn(),
|
||||
};
|
||||
})
|
||||
.mock('../Libraries/ReactNative/requireNativeComponent', () => {
|
||||
return jest.requireActual('./mockNativeComponent');
|
||||
})
|
||||
.mock(
|
||||
'../Libraries/Utilities/verifyComponentAttributeEquivalence',
|
||||
() => function() {},
|
||||
|
|
Загрузка…
Ссылка в новой задаче