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

Remove remaining PropTypes from and modernize Swipable* Classes #21278

Closed
wants to merge 2 commits into from

Conversation

empyrical
Copy link
Contributor

Part of: react-native-community/discussions-and-proposals#29

This PR removes all remaining PropTypes from the classes in Libraries/Experimental/SwipeableRow, and converts SwipeableRow from an old-style createReactClass to a proper subclass of React.Component.

This needed an alternative to TimerMixin, so I created a special <Timer /> component based off of it that can be used through a ref. So it can still use timers that will be automatically terminated when the component is unmounted.

Test Plan:

flow check passes.

A new test for the Timer component based off of the TimerMixin test has been added to Libraries/Components/Timer/__tests__/Timer-test.js

Release Notes:

[GENERAL] [FEATURE] [Libraries/Components/Timer/Timer.js] - Added a new Timer component based off of react-timer-mixin
[GENERAL] [FEATURE] [Libraries/Components/Timer/tests/Timer-test.js] - Added a test for the Timer component
[GENERAL] [ENHANCEMENT] [Libraries/Experimental/SwipeableRow/SwipeableFlatList.js] - Cleaned up and exported props
[GENERAL] [ENHANCEMENT] [Libraries/Experimental/SwipeableRow/SwipeableListView.js] - Removed proptypes and moved prop documentation to the flow types
[GENERAL] [ENHANCEMENT] [Libraries/Experimental/SwipeableRow/SwipeableQuickActionButton.js] - Moved props to a separate declaration and exported them
[GENERAL] [ENHANCEMENT] [Libraries/Experimental/SwipeableRow/SwipeableQuickActions.js] - Converted proptypes to flow types
[GENERAL] [ENHANCEMENT] [Libraries/Experimental/SwipeableRow/SwipeableRow.js] - Converted from createReactClass to a class component, and removed all proptypes
[GENERAL] [MINOR] [Libraries/Lists/ListView/ListView.js] - Exported props type so SwipeableFlatList can use them.
[GENERAL] [ENHANCEMENT] [RNTester/js/SwipeableListViewExample.js] - Finished ES6 modernization

@facebook-github-bot facebook-github-bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Sep 23, 2018
Copy link

@analysis-bot analysis-bot left a comment

Choose a reason for hiding this comment

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

eslint found some issues. You may run yarn prettier or npm run prettier to fix these.

@@ -191,64 +177,73 @@ const SwipeableRow = createReactClass({
</Animated.View>
);

Choose a reason for hiding this comment

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

no-shadow: 'timer' is already declared in the upper scope.

@pull-bot
Copy link

Warnings
⚠️

❗ Big PR - This PR is extremely unlikely to get reviewed because it touches 709 lines.

Generated by 🚫 dangerJS

@elicwhite
Copy link
Member

Awesome!

I believe @yungsters already had a solution for TimerMixin and many things that used to use TimerMixin have already been moved away. Can you decouple those changes from this PR?

const React = require('React');
const SwipeableRow = require('SwipeableRow');
const FlatList = require('FlatList');

type SwipableListProps = {
type Props = {
Copy link
Member

Choose a reason for hiding this comment

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

Can you make this $ReadOnly and exact as well?

type Props = $ReadOnly<{||}>;

renderQuickActions: renderItemType,
};

type Props<ItemT> = SwipableListProps & FlatListProps<ItemT>;
export type SwipableListProps<ItemT> = Props & FlatListProps<ItemT>;
Copy link
Member

Choose a reason for hiding this comment

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

Does this need to be exported?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Can reverse this.


type State = {
type State = {|
Copy link
Member

Choose a reason for hiding this comment

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

👍

rowData: any,
sectionID: string,
rowID: string,
) => React.Element<any>,
Copy link
Member

Choose a reason for hiding this comment

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

Should this be React.Element or React.Node? I'm not sure what this function can return. It probably is a React.Element. 👍

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 had a look around the codebase and for callbacks like this it seems to use Element

const React = require('React');
const StyleSheet = require('StyleSheet');
const View = require('View');

import type {ViewStyleProp} from 'StyleSheet';

export type SwipeableQuickActionsProps = $ReadOnly<{|
Copy link
Member

Choose a reason for hiding this comment

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

Does this need to be exported? We try not to export a bunch of things, only the things that are actually necessary or expected to be used by other files.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That makes sense! Reducing the public api surface area is a good thing.


class SwipeableQuickActions extends React.Component<
SwipeableQuickActionsProps,
> {
render(): React.Node {
// $FlowFixMe found when converting React.createClass to ES6
Copy link
Member

Choose a reason for hiding this comment

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

While typing this component, can you clean up these FlowFixMes as well, as best as possible. This one for example is because children isn't defined in the props: children: React.Node

children?: ?React.Node,
isOpen?: ?boolean,
maxSwipeDistance?: ?number,
maxSwipeDistance: number,
Copy link
Member

Choose a reason for hiding this comment

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

Why this change?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

After I converted it to a React class, it being nullable had a lot of type errors like this:

undefined [1] is not a number.

 [1]  59│   maxSwipeDistance?: ?number,
        :
     306│     const maxSwipeDistance = IS_RTL
     307│       ? -this.props.maxSwipeDistance
     308│       : this.props.maxSwipeDistance;
     309│     this._animateTo(-maxSwipeDistance, duration);
     310│   }
     311│
     312│   _animateToClosedPosition(duration: number = SWIPE_DURATION): void {

But it has a default prop for maxSwipeDistance, so I removed the nullability because the flow docs mention this:

Note: You don’t need to make foo nullable in your Props type. Flow will make sure that foo is optional if you have a default prop for foo.

When it's a creatReactClass again, I should revert this because that notice will no longer be relevant.

};
},
class SwipeableListViewSimpleExample extends React.Component<
$FlowFixMeProps,
Copy link
Member

Choose a reason for hiding this comment

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

Can we do better than this?

var LOREM_IPSUM =
'Lorem ipsum dolor sit amet, ius ad pertinax oportere accommodare, an vix civibus corrumpit referrentur. Te nam case ludus inciderint, te mea facilisi adipiscing. Sea id integre luptatum. In tota sale consequuntur nec. Erat ocurreret mei ei. Eu paulo sapientem vulputate est, vel an accusam intellegam interesset. Nam eu stet pericula reprimique, ea vim illud modus, putant invidunt reprehendunt ne qui.';

const LOREM_IPSUM = [
Copy link
Member

Choose a reason for hiding this comment

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

Could also use template literal

@elicwhite
Copy link
Member

This is great. Thanks for cleaning up / updating these files! For the sections that might require more back and forth or are less obvious on the approach, splitting those changes out can let us merge the rest of it and mark them off the list as completed!

@empyrical
Copy link
Contributor Author

For the TimerMixin thing, I will have to revert it back to a createReactClass for now. I tried looking around and seeing what was being used as an alternative to TimerMixin before I did that, but I couldn't see it.

@empyrical
Copy link
Contributor Author

I have made a copy of the current version of this branch so my Timer component is more easily referenced to once I update this PR to the feedback:

https://github.com/empyrical/react-native/tree/swipable-updating-bak/Libraries/Components/Timer

@elicwhite
Copy link
Member

elicwhite commented Sep 23, 2018

Apparently @yungsters's approach was to just inline the timer:

this._timerID = setTimeout(…);

And then in componentWillUnmount:

if (this._timerID != null) {
  clearTimeout(this._timerID);
}

It seems simple enough and easier to read than having a whole component. What do you think?

@empyrical
Copy link
Contributor Author

empyrical commented Sep 23, 2018

I am going to redo this again as separate, smaller pull requests.

@empyrical empyrical closed this Sep 23, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants