Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add HostComponent type to ReactNative #16898

Merged
merged 3 commits into from
Sep 26, 2019

Conversation

elicwhite
Copy link
Member

@elicwhite elicwhite commented Sep 25, 2019

Note: This change was already landed to React Native in facebook/react-native@69c38e5 so this commit just updates the types in React core to make the next sync not have conflicts.


In React Native there are three types of "Native" components.

createReactClass with NativeMethodsMixin
class MyComponent extends ReactNative.NativeComponent
requireNativeComponent('RCTView')

The implementation for how to handle all three of these exists in the React Native Renderer. Refs attached to components created via these methods provide a set of functions such as

.measure
.measureInWindow
.measureLayout
.setNativeProps

These methods have been used for our core components in the repo to provide a consistent API. Many of the APIs in React Native require a reactTag to a host component. This is acquired by calling findNodeHandle with any component. findNodeHandle works with the first two approaches.

For a lot of our new Fabric APIs, we will require passing a ref to a HostComponent directly instead of relying on findNodeHandle to tunnel through the component tree as that behavior isn't safe with React concurrent mode.

The goal of this change is to enable us to differentiate between components created with requireNativeComponent and the other types. This will be needed to be able to safely type the new APIs.

For existing components that should support being a host component but need to use some JS behavior in a wrapper, they should use forwardRef. The majority of React Native's core components were migrated to use forwardRef last year. Components that can't use forwardRef will need to have a method like getNativeRef() to get access to the underlying host component ref.

Note, we will need follow up changes as well as changes to the React Renderer in the React repo to fully utilize this new type.

@sizebot
Copy link

sizebot commented Sep 25, 2019

No significant bundle size changes to report.

Generated by 🚫 dangerJS against db60405

@@ -161,7 +161,7 @@ export default function(
measureLayout: function(
relativeToNativeNode: number | Object,
onSuccess: MeasureLayoutOnSuccessCallback,
onFail: () => void /* currently unused */,
onFail?: () => void /* currently unused */,
Copy link
Member Author

Choose a reason for hiding this comment

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

This was always optional in the types used in React Native, but because the two types are duplicated in ReactNativeTypes, they must have fallen out of sync.

@@ -151,9 +151,9 @@ class ReactFabricHostComponent {
}

measureLayout(
relativeToNativeNode: number | Object,
Copy link
Member Author

Choose a reason for hiding this comment

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

Yay!

Copy link
Contributor

Choose a reason for hiding this comment

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

I realize it's not part of this change, but should the warningWithoutStack inside of this function (and the one in packages/react-native-renderer/src/ReactNativeFiberHostComponent.js) be __DEV__ gated?

Copy link
Member Author

Choose a reason for hiding this comment

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

warningWithoutStack internally has a dev check and is a no-op in dev.

@@ -8,7 +8,7 @@
* @flow
*/

import React from 'react';
import * as React from 'react';
Copy link
Member Author

Choose a reason for hiding this comment

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

This is needed because we are now importing types from React. ElementRef, and AbstractComponent.

): void,
setNativeProps(nativeProps: Object): void,
};

export type NativeMethodsMixinType = NativeMethods;
export type HostComponent<T> = React.AbstractComponent<
Copy link
Member Author

Choose a reason for hiding this comment

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

So simple. So clean.

facebook-github-bot pushed a commit to facebook/react-native that referenced this pull request Sep 26, 2019
Summary:
I upstreamed the changes to this file from previous commits to React in this (unlanded) PR: facebook/react#16898 (comment)

I had to make some additional changes to be able to make Flow pass there. Bringing those changes back to FBSource as well. Having this change made here will make the next sync easier as we won't have to deal with conflicts then.

Changelog:
[Internal]

Reviewed By: cpojer

Differential Revision: D17586781

fbshipit-source-id: 4be8376d0af4fb5d63410afaaf5bb0005d992981
@@ -151,9 +151,9 @@ class ReactFabricHostComponent {
}

measureLayout(
relativeToNativeNode: number | Object,
Copy link
Contributor

Choose a reason for hiding this comment

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

I realize it's not part of this change, but should the warningWithoutStack inside of this function (and the one in packages/react-native-renderer/src/ReactNativeFiberHostComponent.js) be __DEV__ gated?

relativeToNativeNode.canonical &&
relativeToNativeNode.canonical._nativeTag
) {
/* $FlowFixMe canonical doesn't exist on the node.
I think this branch is dead and will remove it in a followup */
Copy link
Contributor

Choose a reason for hiding this comment

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

I was wondering if the change from Object -> ReactNativeFiberHostComponent made sense given relativeToNativeNode.canonical but I assume it's okay?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah.

When I added this option I wrote tests that called this with createClass, ReactNativeNativeComponent and a host component. Nothing triggers this branch. That's why I think this is dead.

Worst case, nothing except some of our Fabric screens are using this API yet and we'll get quick signal if I'm wrong once we delete it. But it's unrelated to this type change.

@@ -8,7 +8,7 @@
* @flow
*/

import React from 'react';
import React, {type ElementRef, type AbstractComponent} from 'react';
Copy link
Contributor

Choose a reason for hiding this comment

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

I didn't know you could mix ES imports and type imports this way 😮

export type NativeMethodsMixinType = NativeMethods;
export type HostComponent<T> = AbstractComponent<
T,
$ReadOnly<$Exact<NativeMethods>>,
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think I understand the purpose of $ReadOnly or $Exact here.

Copy link
Member Author

Choose a reason for hiding this comment

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

From @jbrown215:

Definitely consider making the instance type of HostComponent read-only-- all of those function names seem like things you don't want people to overwrite. If the object really has no other properties, you can also make it exact. If it might, don't, otherwise spreading that object would be unsound (not that I can see a reason why someone would want to spread it?)

@elicwhite elicwhite merged commit db8afe4 into facebook:master Sep 26, 2019
@elicwhite elicwhite deleted the host-component branch September 26, 2019 21:42
rickhanlonii pushed a commit to rickhanlonii/react that referenced this pull request Oct 9, 2019
* Add HostComponent type to ReactNative

* Use type alias imports instead of wildcard

* Fix forgotten Object in measureLayout type
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