react/packages/react-native-renderer/src/NativeMethodsMixin.js

223 lines
7.8 KiB
JavaScript
Raw Normal View History

2016-03-25 06:40:52 +08:00
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
2016-03-25 06:40:52 +08:00
*
* @flow
*/
import type {
MeasureInWindowOnSuccessCallback,
MeasureLayoutOnSuccessCallback,
MeasureOnSuccessCallback,
NativeMethodsMixinType,
ReactNativeBaseComponentViewConfig,
} from './ReactNativeTypes';
Drop Haste (#11303) * Use relative paths in packages/react * Use relative paths in packages/react-art * Use relative paths in packages/react-cs * Use relative paths in other packages * Fix as many issues as I can This uncovered an interesting problem where ./b from package/src/a would resolve to a different instantiation of package/src/b in Jest. Either this is a showstopper or we can solve it by completely fobbidding remaining /src/. * Fix all tests It seems we can't use relative requires in tests anymore. Otherwise Jest becomes confused between real file and symlink. https://github.com/facebook/jest/issues/3830 This seems bad... Except that we already *don't* want people to create tests that import individual source files. All existing cases of us doing so are actually TODOs waiting to be fixed. So perhaps this requirement isn't too bad because it makes bad code looks bad. Of course, if we go with this, we'll have to lint against relative requires in tests. It also makes moving things more painful. * Prettier * Remove @providesModule * Fix remaining Haste imports I missed earlier * Fix up paths to reflect new flat structure * Fix Flow * Fix CJS and UMD builds * Fix FB bundles * Fix RN bundles * Prettier * Fix lint * Fix warning printing and error codes * Fix buggy return * Fix lint and Flow * Use Yarn on CI * Unbreak Jest * Fix lint * Fix aliased originals getting included in DEV Shouldn't affect correctness (they were ignored) but fixes DEV size regression. * Record sizes * Fix weird version in package.json * Tweak bundle labels * Get rid of output option by introducing react-dom/server.node * Reconciler should depend on prop-types * Update sizes last time
2017-10-25 07:55:00 +08:00
import invariant from 'shared/invariant';
// Modules provided by RN:
import TextInputState from 'TextInputState';
import UIManager from 'UIManager';
2016-03-25 06:40:52 +08:00
import * as ReactNativeAttributePayload from './ReactNativeAttributePayload';
import {
mountSafeCallback,
throwOnStylesProp,
warnForStyleProps,
} from './NativeMethodsMixinUtils';
2016-03-25 06:40:52 +08:00
export default function(
findNodeHandle: any => ?number,
findHostInstance: any => any,
) {
2016-03-25 06:40:52 +08:00
/**
* `NativeMethodsMixin` provides methods to access the underlying native
* component directly. This can be useful in cases when you want to focus
* a view or measure its on-screen dimensions, for example.
2016-03-25 06:40:52 +08:00
*
* The methods described here are available on most of the default components
* provided by React Native. Note, however, that they are *not* available on
* composite components that aren't directly backed by a native view. This will
* generally include most components that you define in your own app. For more
* information, see [Direct
* Manipulation](docs/direct-manipulation.html).
2016-03-25 06:40:52 +08:00
*
* Note the Flow $Exact<> syntax is required to support mixins.
* React createClass mixins can only be used with exact types.
2016-03-25 06:40:52 +08:00
*/
const NativeMethodsMixin: $Exact<NativeMethodsMixinType> = {
/**
* Determines the location on screen, width, and height of the given view and
* returns the values via an async callback. If successful, the callback will
* be called with the following arguments:
*
* - x
* - y
* - width
* - height
* - pageX
* - pageY
*
* Note that these measurements are not available until after the rendering
* has been completed in native. If you need the measurements as soon as
* possible, consider using the [`onLayout`
* prop](docs/view.html#onlayout) instead.
*/
measure: function(callback: MeasureOnSuccessCallback) {
UIManager.measure(
findNodeHandle(this),
mountSafeCallback(this, callback),
);
},
/**
* Determines the location of the given view in the window and returns the
* values via an async callback. If the React root view is embedded in
* another native view, this will give you the absolute coordinates. If
* successful, the callback will be called with the following
* arguments:
*
* - x
* - y
* - width
* - height
*
* Note that these measurements are not available until after the rendering
* has been completed in native.
*/
measureInWindow: function(callback: MeasureInWindowOnSuccessCallback) {
UIManager.measureInWindow(
findNodeHandle(this),
mountSafeCallback(this, callback),
);
},
/**
* Like [`measure()`](#measure), but measures the view relative an ancestor,
* specified as `relativeToNativeNode`. This means that the returned x, y
* are relative to the origin x, y of the ancestor view.
*
* As always, to obtain a native node handle for a component, you can use
* `findNodeHandle(component)`.
*/
measureLayout: function(
relativeToNativeNode: number,
onSuccess: MeasureLayoutOnSuccessCallback,
onFail: () => void /* currently unused */,
) {
UIManager.measureLayout(
findNodeHandle(this),
relativeToNativeNode,
mountSafeCallback(this, onFail),
mountSafeCallback(this, onSuccess),
);
},
/**
* This function sends props straight to native. They will not participate in
* future diff process - this means that if you do not include them in the
* next render, they will remain active (see [Direct
* Manipulation](docs/direct-manipulation.html)).
*/
setNativeProps: function(nativeProps: Object) {
// Class components don't have viewConfig -> validateAttributes.
// Nor does it make sense to set native props on a non-native component.
// Instead, find the nearest host component and set props on it.
// Use findNodeHandle() rather than findNodeHandle() because
// We want the instance/wrapper (not the native tag).
let maybeInstance;
// Fiber errors if findNodeHandle is called for an umounted component.
// Tests using ReactTestRenderer will trigger this case indirectly.
// Mimicking stack behavior, we should silently ignore this case.
// TODO Fix ReactTestRenderer so we can remove this try/catch.
try {
maybeInstance = findHostInstance(this);
} catch (error) {}
// If there is no host component beneath this we should fail silently.
// This is not an error; it could mean a class component rendered null.
if (maybeInstance == null) {
return;
}
const viewConfig: ReactNativeBaseComponentViewConfig =
maybeInstance.viewConfig;
if (__DEV__) {
warnForStyleProps(nativeProps, viewConfig.validAttributes);
}
const updatePayload = ReactNativeAttributePayload.create(
nativeProps,
viewConfig.validAttributes,
);
2016-03-25 06:40:52 +08:00
// Avoid the overhead of bridge calls if there's no update.
// This is an expensive no-op for Android, and causes an unnecessary
// view invalidation for certain components (eg RCTTextInput) on iOS.
if (updatePayload != null) {
UIManager.updateView(
maybeInstance._nativeTag,
viewConfig.uiViewClassName,
updatePayload,
);
}
},
/**
* Requests focus for the given input or view. The exact behavior triggered
* will depend on the platform and type of view.
*/
focus: function() {
TextInputState.focusTextInput(findNodeHandle(this));
},
/**
* Removes focus from an input or view. This is the opposite of `focus()`.
*/
blur: function() {
TextInputState.blurTextInput(findNodeHandle(this));
},
RFC 6: Deprecate unsafe lifecycles (#12028) * Added unsafe_* lifecycles and deprecation warnings If the old lifecycle hooks (componentWillMount, componentWillUpdate, componentWillReceiveProps) are detected, these methods will be called and a deprecation warning will be logged. (In other words, we do not check for both the presence of the old and new lifecycles.) This commit is expected to fail tests. * Ran lifecycle hook codemod over project This should handle the bulk of the updates. I will manually update TypeScript and CoffeeScript tests with another commit. The actual command run with this commit was: jscodeshift --parser=flow -t ../react-codemod/transforms/rename-unsafe-lifecycles.js ./packages/**/src/**/*.js * Manually migrated CoffeeScript and TypeScript tests * Added inline note to createReactClassIntegration-test Explaining why lifecycles hooks have not been renamed in this test. * Udated NativeMethodsMixin with new lifecycle hooks * Added static getDerivedStateFromProps to ReactPartialRenderer Also added a new set of tests focused on server side lifecycle hooks. * Added getDerivedStateFromProps to shallow renderer Also added warnings for several cases involving getDerivedStateFromProps() as well as the deprecated lifecycles. Also added tests for the above. * Dedupe and DEV-only deprecation warning in server renderer * Renamed unsafe_* prefix to UNSAFE_* to be more noticeable * Added getDerivedStateFromProps to ReactFiberClassComponent Also updated class component and lifecyle tests to cover the added functionality. * Warn about UNSAFE_componentWillRecieveProps misspelling * Added tests to createReactClassIntegration for new lifecycles * Added warning for stateless functional components with gDSFP * Added createReactClass test for static gDSFP * Moved lifecycle deprecation warnings behind (disabled) feature flag Updated tests accordingly, by temporarily splitting tests that were specific to this feature-flag into their own, internal tests. This was the only way I knew of to interact with the feature flag without breaking our build/dist tests. * Tidying up * Tweaked warning message wording slightly Replaced 'You may may have returned undefined.' with 'You may have returned undefined.' * Replaced truthy partialState checks with != null * Call getDerivedStateFromProps via .call(null) to prevent type access * Move shallow-renderer didWarn* maps off the instance * Only call getDerivedStateFromProps if props instance has changed * Avoid creating new state object if not necessary * Inject state as a param to callGetDerivedStateFromProps This value will be either workInProgress.memoizedState (for updates) or instance.state (for initialization). * Explicitly warn about uninitialized state before calling getDerivedStateFromProps. And added some new tests for this change. Also: * Improved a couple of falsy null/undefined checks to more explicitly check for null or undefined. * Made some small tweaks to ReactFiberClassComponent WRT when and how it reads instance.state and sets to null. * Improved wording for deprecation lifecycle warnings * Fix state-regression for module-pattern components Also add support for new static getDerivedStateFromProps method
2018-01-20 01:36:46 +08:00
};
if (__DEV__) {
// hide this from Flow since we can't define these properties outside of
// __DEV__ without actually implementing them (setting them to undefined
// isn't allowed by ReactClass)
const NativeMethodsMixin_DEV = (NativeMethodsMixin: any);
invariant(
!NativeMethodsMixin_DEV.componentWillMount &&
!NativeMethodsMixin_DEV.componentWillReceiveProps &&
!NativeMethodsMixin_DEV.UNSAFE_componentWillMount &&
!NativeMethodsMixin_DEV.UNSAFE_componentWillReceiveProps,
'Do not override existing functions.',
);
// TODO (bvaughn) Remove cWM and cWRP in a future version of React Native,
// Once these lifecycles have been remove from the reconciler.
NativeMethodsMixin_DEV.componentWillMount = function() {
throwOnStylesProp(this, this.props);
};
NativeMethodsMixin_DEV.componentWillReceiveProps = function(newProps) {
throwOnStylesProp(this, newProps);
};
NativeMethodsMixin_DEV.UNSAFE_componentWillMount = function() {
throwOnStylesProp(this, this.props);
};
NativeMethodsMixin_DEV.UNSAFE_componentWillReceiveProps = function(
newProps,
) {
throwOnStylesProp(this, newProps);
};
// React may warn about cWM/cWRP/cWU methods being deprecated.
// Add a flag to suppress these warnings for this special case.
// TODO (bvaughn) Remove this flag once the above methods have been removed.
NativeMethodsMixin_DEV.componentWillMount.__suppressDeprecationWarning = true;
NativeMethodsMixin_DEV.componentWillReceiveProps.__suppressDeprecationWarning = true;
}
return NativeMethodsMixin;
2016-03-25 06:40:52 +08:00
}