Skip to content

Create ReactNativeComponent Abstract Class#9814

Merged
yungsters merged 1 commit intofacebook:masterfrom
yungsters:react-native-component
May 31, 2017
Merged

Create ReactNativeComponent Abstract Class#9814
yungsters merged 1 commit intofacebook:masterfrom
yungsters:react-native-component

Conversation

@yungsters
Copy link
Copy Markdown
Contributor

@yungsters yungsters commented May 30, 2017

Summary:
This creates ReactNativeComponent, the modern replacement for NativeMethodsMixin.

This class is going to allow us to start migrating React Native off React.createClass(...) into a typesafe, class-based brave new world.

This also introduces IReactNativeComponent, an interface that enforces consistency between ReactNativeComponent and ReactNativeFiberHostComponent.

@yungsters yungsters self-assigned this May 30, 2017
@yungsters yungsters requested a review from bvaughn May 30, 2017 18:34
@yungsters yungsters force-pushed the react-native-component branch from e6c4640 to 4095e7c Compare May 30, 2017 18:34
@yungsters yungsters force-pushed the react-native-component branch 2 times, most recently from 50ed206 to 6d0cd79 Compare May 30, 2017 18:35
} = require('ReactNative');

module.exports =
__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactNativeComponent;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be public API of RN? I was surprised FB code uses NativeMethodsMixin but we don't seem to expose it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good. Any objections to exporting it as ReactNative.Component?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this would confuse people because it's easy to mistake imports. Maybe ReactNative.NativeComponent? In which case would one use it?

Copy link
Copy Markdown
Contributor

@bvaughn bvaughn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ReactNative imports were causing the failure, I'd guess because of circular references. Try patching in:

diff --git a/src/renderers/native/ReactNativeComponent.js b/src/renderers/native/ReactNativeComponent.js
index 2671d79e3..0565bde50 100644
--- a/src/renderers/native/ReactNativeComponent.js
+++ b/src/renderers/native/ReactNativeComponent.js
@@ -13,8 +13,7 @@
 
 'use strict';
 
-const React = require('React');
-const ReactNative = require('ReactNative');
+const React = require('react');
 const ReactNativeAttributePayload = require('ReactNativeAttributePayload');
 const ReactNativeFeatureFlags = require('ReactNativeFeatureFlags');
 const TextInputState = require('TextInputState');
@@ -34,6 +33,10 @@ import type {
   ReactNativeBaseComponentViewConfig,
 } from 'ReactNativeViewConfigRegistry';
 
+const findNumericNodeHandle = ReactNativeFeatureFlags.useFiber
+  ? require('findNumericNodeHandleFiber')
+  : require('findNumericNodeHandleStack');
+
 /**
  * Superclass that provides methods to access the underlying native component.
  * This can be useful when you want to focus a view or measure its dimensions.
@@ -56,14 +59,14 @@ class ReactNativeComponent<DefaultProps, Props, State>
    * Removes focus. This is the opposite of `focus()`.
    */
   blur(): void {
-    TextInputState.blurTextInput(ReactNative.findNodeHandle(this));
+    TextInputState.blurTextInput(findNumericNodeHandle(this));
   }
 
   /**
    * Requests focus. The exact behavior depends on the platform and view.
    */
   focus(): void {
-    TextInputState.focusTextInput(ReactNative.findNodeHandle(this));
+    TextInputState.focusTextInput(findNumericNodeHandle(this));
   }
 
   /**
@@ -83,7 +86,7 @@ class ReactNativeComponent<DefaultProps, Props, State>
    */
   measure(callback: MeasureOnSuccessCallback): void {
     UIManager.measure(
-      ReactNative.findNodeHandle(this),
+      findNumericNodeHandle(this),
       mountSafeCallback(this, callback),
     );
   }
@@ -103,7 +106,7 @@ class ReactNativeComponent<DefaultProps, Props, State>
    */
   measureInWindow(callback: MeasureInWindowOnSuccessCallback): void {
     UIManager.measureInWindow(
-      ReactNative.findNodeHandle(this),
+      findNumericNodeHandle(this),
       mountSafeCallback(this, callback),
     );
   }
@@ -120,7 +123,7 @@ class ReactNativeComponent<DefaultProps, Props, State>
     onFail: () => void /* currently unused */,
   ): void {
     UIManager.measureLayout(
-      ReactNative.findNodeHandle(this),
+      findNumericNodeHandle(this),
       relativeToNativeNode,
       mountSafeCallback(this, onFail),
       mountSafeCallback(this, onSuccess),
@@ -134,14 +137,6 @@ class ReactNativeComponent<DefaultProps, Props, State>
    * Manipulation](docs/direct-manipulation.html)).
    */
   setNativeProps(nativeProps: Object): void {
-    // Ensure ReactNative factory function has configured findNodeHandle.
-    // Requiring it won't execute the factory function until first referenced.
-    // It's possible for tests that use ReactTestRenderer to reach this point,
-    // Without having executed ReactNative.
-    // Defer the factory function until now to avoid a cycle with UIManager.
-    // TODO (bvaughn) Remove this once ReactNativeStack is dropped.
-    require('ReactNative');
-
     injectedSetNativeProps(this, nativeProps);
   }
 }

onFail: () => void,
): void,
setNativeProps(nativeProps: Object): void,
}
Copy link
Copy Markdown
Contributor

@bvaughn bvaughn May 30, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer to use NativeMethodsMixinType and add a "TODO" comment to replace it with an interface once NativeMethodsMixin is gone. This works (I tested it a few days ago) and avoids having to maintain mirror types.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll change ReactNativeComponent to use NativeMethodsMixinType like you did in ReactNativeFiberHostComponent, but disclaimer... the same trick does not actually work for ReactNativeComponent:

(ReactNativeComponent.prototype: NativeMethodsMixinType);

Unlike for ReactNativeFiberHostComponent, Flow does not complain if any of the methods are missing. I suspect this is because ReactBaseClasses (and therefore React.Component) is not Flow-typed. Getting rid of extends React.Component fixes this, but we obviously cannot do that.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, rats! That's unfortunate. 😦

In that case, then I guess the duplicate type is a reasonable workaround. If we use it, we should just remove the (ReactNativeComponent.prototype: NativeMethodsMixinType) cast too I guess.

* ReactNativeFiber).
*/
class ReactNativeFiberHostComponent {
class ReactNativeFiberHostComponent implements IReactNativeComponent {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is redundant with the NativeMethodsMixinType type already being used.

@yungsters
Copy link
Copy Markdown
Contributor Author

Try patching in: [...]

@bvaughn Thanks for that suggestion. However, I still run into the following build error:

'React' is imported by src/renderers/native/ReactNativeComponent.js, but could not be resolved – treating it as an external dependency

Although ReactNative might have also been an eventual cause of build breakage, I think React is for some reason also not permitted or a circular dependency.

@bvaughn
Copy link
Copy Markdown
Contributor

bvaughn commented May 30, 2017

Yeah, my diff also replaced "React" with "react":

-const React = require('React');
-const ReactNative = require('ReactNative');
+const React = require('react');

@yungsters yungsters force-pushed the react-native-component branch 2 times, most recently from d0d3521 to 8cbfbc6 Compare May 31, 2017 00:52
@yungsters
Copy link
Copy Markdown
Contributor Author

Fixed the build and replaced the shim with ReactNative.NativeComponent.

Copy link
Copy Markdown
Contributor

@bvaughn bvaughn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we're exposing ReactNativeComponent via ReactNative.NativeComponent then we can ditch the shim and the accessor on __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactNativeComponent

@yungsters
Copy link
Copy Markdown
Contributor Author

Oh, what... I thought I removed that already.

@yungsters yungsters force-pushed the react-native-component branch from 8cbfbc6 to 97797f8 Compare May 31, 2017 03:55

// Used by react-native-github/Libraries/ components
ReactGlobalSharedState: require('ReactGlobalSharedState'), // Systrace
ReactNativeComponent: require('ReactNativeComponent'),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be removed too 😁


// Used by react-native-github/Libraries/ components
ReactGlobalSharedState: require('ReactGlobalSharedState'), // Systrace
ReactNativeComponent: require('ReactNativeComponent'),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And this 😁

@yungsters
Copy link
Copy Markdown
Contributor Author

Hmm... I think that I screwed something up with Git.

Summary:
This creates `ReactNativeComponent`, the modern replacement for `NativeMethodsMixin`.

This class is going to allow us to start migrating React Native off `React.createClass(...)` into a typesafe, class-based brave new world.

This also introduces `IReactNativeComponent`, an interface that enforces consistency between `ReactNativeComponent` and `ReactNativeFiberHostComponent`.
@yungsters
Copy link
Copy Markdown
Contributor Author

Thank you for the thorough review. 👍

@yungsters yungsters force-pushed the react-native-component branch from 97797f8 to 604252c Compare May 31, 2017 04:21
Copy link
Copy Markdown
Contributor

@bvaughn bvaughn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problem! 👍

@yungsters yungsters merged commit 3f75ea8 into facebook:master May 31, 2017
@yungsters yungsters deleted the react-native-component branch May 31, 2017 04:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants