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

refactor: separate Screen native props and public API #2423

Merged

Conversation

maciekstosio
Copy link
Contributor

@maciekstosio maciekstosio commented Oct 21, 2024

Description

Separating native types and public API for Screen component. The core idea behind this change is that I removed hardcoded as ScreenProps and try to conform public API to NativeProps accepted by Codegen, with some transformations if necessary.

Changes

The biggest change is not casting Native to Component with ScreenProps.

Screenshots / GIFs

N/A

Checklist

src/types.tsx Outdated Show resolved Hide resolved
Copy link
Member

@kkafar kkafar left a comment

Choose a reason for hiding this comment

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

I havent read carefully, just skimmed through the changes. Leaving my initial impressions below

src/components/Screen.tsx Outdated Show resolved Hide resolved
@@ -13,6 +13,10 @@ import type {
// eslint-disable-next-line @typescript-eslint/ban-types
type ScreenEvent = Readonly<{}>;

type ScreenTargetEvent = Readonly<{
Copy link
Member

Choose a reason for hiding this comment

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

What is the reasoning behind this change here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is how our public API looks:

  onAppear?: (e: NativeSyntheticEvent<TargetedEvent>) => void;

Thus, the change. I needed to write in on my won cause TargetedEvent is {target: number}, and Codegen doesn't like number :D

Copy link
Contributor Author

@maciekstosio maciekstosio Oct 22, 2024

Choose a reason for hiding this comment

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

Changed in: cd5ccea. We decided not to change it because updating NativeProps will produce unused properties in C++ - unnecessarily wasting memory. My understanding is that the target value in an event is filled by the ReactNative thus mismatch between NativeProps and React props.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@kkafar If I missed something would be good to put it here, as I linked the discussion in comment.

src/index.tsx Outdated Show resolved Hide resolved
src/types.tsx Outdated Show resolved Hide resolved
src/types.tsx Outdated
Comment on lines 220 to 222
onGestureCancel?: (
e: NativeSyntheticEvent<Readonly<Record<string, never>>>,
) => void;
Copy link
Member

Choose a reason for hiding this comment

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

Why do we change this?

Copy link
Contributor Author

@maciekstosio maciekstosio Oct 21, 2024

Choose a reason for hiding this comment

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

To conform with NativeProps, I don't think this is breaking for anyone as we don't pass anything in this callback. I just described nothing differently.

Copy link
Member

Choose a reason for hiding this comment

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

Do we stil need this change? I expect this to not change in effect of splitting out props of native components.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, nothing changed here

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Reverted in: c51f636

## Description

Sync ScreenNative and ModalScreenNative props.
…-public-API' of github.com:software-mansion/react-native-screens into @maciekstosio/Separate-native-Screen-interface-from-the-public-API
@maciekstosio maciekstosio marked this pull request as ready for review October 22, 2024 12:26
Copy link
Member

@kkafar kkafar left a comment

Choose a reason for hiding this comment

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

Left few remarks.

Comment on lines 17 to 18
import NativeScreen from '../fabric/ScreenNativeComponent';
import ModalScreenNative from '../fabric/ModalScreenNativeComponent';
Copy link
Member

Choose a reason for hiding this comment

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

Let's keep one convention. I believe we use xxxNativeComponent everywhere.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

src/types.tsx Outdated
Comment on lines 220 to 222
onGestureCancel?: (
e: NativeSyntheticEvent<Readonly<Record<string, never>>>,
) => void;
Copy link
Member

Choose a reason for hiding this comment

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

Do we stil need this change? I expect this to not change in effect of splitting out props of native components.

Comment on lines 33 to 43
type NativeScreenOverrideProps = Omit<
React.ComponentPropsWithRef<typeof NativeScreen>,
'onAppear' | 'onDisappear' | 'onWillAppear' | 'onWillDisappear'
> &
SharedOverride;

type NativeModalScreenOverrideProps = Omit<
React.ComponentPropsWithRef<typeof ModalScreenNative>,
'onAppear' | 'onDisappear' | 'onWillAppear' | 'onWillDisappear'
> &
SharedOverride;
Copy link
Member

Choose a reason for hiding this comment

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

Single type should be enough. ModalScreen & Screen should use the same types I believe.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I didn't want to combine them as they are different entities we try to sync them, but when casting, I think using just one could lead to undetected bugs.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We could go with something like this:

type SharedOverride = {
    onAppear?: ScreenProps['onAppear'];
    onDisappear?: ScreenProps['onDisappear'];
    onWillAppear?: ScreenProps['onWillAppear'];
    onWillDisappear?: ScreenProps['onWillDisappear'];
}

type NativeScreenOverrideProps = Omit<
  React.ComponentPropsWithRef<typeof ScreenNativeComponent | typeof ModalScreenComponent>,
  "onAppear" | "onDisappear" | "onWillAppear" | "onWillDisappear"
> & SharedOverride; 

const AnimatedNativeScreen = Animated.createAnimatedComponent(ScreenNativeComponent as React.ComponentType<NativeScreenOverrideProps>);
const AnimatedNativeModalScreen = Animated.createAnimatedComponent(ModalScreenComponent as React.ComponentType<NativeScreenOverrideProps>);

It should actually help us with some of out of sync problems and solves both issues

Copy link
Member

Choose a reason for hiding this comment

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

There should be no differences in types between these components. At least for now - so single type is enough.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Comment on lines 33 to 37
type NativeScreenOverrideProps = Omit<
React.ComponentPropsWithRef<typeof NativeScreen>,
'onAppear' | 'onDisappear' | 'onWillAppear' | 'onWillDisappear'
> &
SharedOverride;
Copy link
Member

Choose a reason for hiding this comment

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

Also, can we use Omit somehow directly with SharedOverride, so that there is single source of truth? keyof or something?

Copy link
Member

Choose a reason for hiding this comment

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

Just as I've done here

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Member

@kkafar kkafar left a comment

Choose a reason for hiding this comment

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

Okay, I think we're good. You can try to solve the typescript issue with empty object for onGestureCancel callback in separate PR 🙏🏻

@kkafar kkafar merged commit 19866ef into main Oct 22, 2024
6 checks passed
@kkafar kkafar deleted the @maciekstosio/Separate-native-Screen-interface-from-the-public-API branch October 22, 2024 15:07
maciekstosio added a commit that referenced this pull request Oct 25, 2024
## Description

Continuation of
#2423.
Separate public `ScreenStackProps` and `NativeProps` by not casting
NativeComponent as `React.ComponentType<ScreenStackProps> `.

## Checklist

- [ ] Ensured that CI passes
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants