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

[ListView] Allow different types of ScrollView to be composed #785

Closed
wants to merge 1 commit into from

Conversation

ide
Copy link
Contributor

@ide ide commented Apr 9, 2015

This enables code like:

<ListView renderScrollView={() => <CustomScrollView />} />

where CustomScrollView might be inverted or support pull-to-refresh, etc.

@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 Apr 9, 2015
@ide ide force-pushed the listview-composition branch 3 times, most recently from 21189f6 to eeaa260 Compare April 12, 2015 08:16
@ide
Copy link
Contributor Author

ide commented Apr 12, 2015

cc @vjeux, this implements the composition prop discussed in #766

@ide
Copy link
Contributor Author

ide commented Apr 12, 2015

It could be better to name the prop renderScrollComponent or renderScrollableView since it's OK to return components that aren't exactly <ScrollView>. Is renderScrollView confusing?

@ide ide force-pushed the listview-composition branch 4 times, most recently from fee4b89 to e767a5c Compare April 16, 2015 01:13
var scrollView = renderScrollView();
return React.cloneElement(scrollView, {
...props,
...scrollView.props,
Copy link
Contributor

Choose a reason for hiding this comment

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

why do you need to do that?

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 want to merge the ListView's props (e.g. scrollEventThrottle) with the underlying ScrollView's props if renderScrollView returned something like <ScrollView pageSize={10} />, but the implementation in this diff is not flexible enough. I'll update it to your renderScrollView(props) idea after I try composing some ScrollViews together.

@ide ide force-pushed the listview-composition branch 2 times, most recently from f364404 to 8279015 Compare April 16, 2015 04:53
@ide ide force-pushed the listview-composition branch 3 times, most recently from 2ac5ede to eae66d4 Compare April 28, 2015 01:23
@ide
Copy link
Contributor Author

ide commented May 6, 2015

catping

@frantic
Copy link
Contributor

frantic commented May 6, 2015

I tried this some time ago, but it turned out to be a disaster - RefreshableScrollView scrollview didn't play nicely with ListView because ListView depends on stickyHeaderIndices prop of ScrollView and assumes there are no other views besides those managed by ListView. Unfortunately RefreshableScrollView does add extra views and shifts those indices, resulting in incorrect ListView rendering...

@ide have you tried

<ListView renderScrollView={() => <RefreshableScrollView />} />

with sections that have sticky headers?

@ide
Copy link
Contributor Author

ide commented May 6, 2015

@frantic: my RefreshableScrollView (not yet open-sourced) doesn't modify the header indices or children so composing it with a ListView works. You may actually want to look at using it when it is open-source since it handles more edge cases and features than I believe the FB implementation does. Along with #766 this composition API lets me create reversed, refreshable, infinite-scroll list views for example.

@frantic
Copy link
Contributor

frantic commented May 6, 2015

@ide mind sharing it? I guess we could merge it into the main repo if you want.

@ide
Copy link
Contributor Author

ide commented May 6, 2015

Yep, my plan is to share it in the near future once it is easy to use out of the box, since I am still working on the default spinner component. I will probably publish it to npm since it is pure JS code; it will be as simple as npm install react-native-refreshable-scroll-view and no need to add code to core.

* A function that returns the scroll view in which the list rows are
* rendered. Defaults to returning a ScrollView with the given props.
*/
renderScrollView: React.PropTypes.func.isRequired,
Copy link
Contributor

Choose a reason for hiding this comment

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

No reason to mark this as required since it has a default implementation.

Copy link
Contributor

Choose a reason for hiding this comment

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

Also, I agree that "ScrollView" is a little confusing here - renderScrollComponent might be better. Can you update?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will update with a renamed version.

Regarding isRequired, I understand it to mean that the type of this.props.renderScrollView is Function instead of ?Function in Flow-speak. So because we're saying the prop is non-null (which is true because of the default value from getDefaultProps), Flow won't complain about this.props.renderScrollView() needing a null check.

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh, interesting, does flow even apply to non-es6 class-style propTypes?
On Thu, Jun 11, 2015 at 4:29 PM James Ide notifications@github.com wrote:

In Libraries/CustomComponents/ListView/ListView.js
#785 (comment):

@@ -164,6 +164,13 @@ var ListView = React.createClass({
/
renderSectionHeader: PropTypes.func,
/
*

  • \* (props) => renderable
    
  • *
    
  • \* A function that returns the scroll view in which the list rows are
    
  • \* rendered. Defaults to returning a ScrollView with the given props.
    
  • */
    
  • renderScrollView: React.PropTypes.func.isRequired,

Will update with a renamed version.

Regarding isRequired, I understand it to mean that the type of
this.props.renderScrollView is Function instead of ?Function in
Flow-speak. So because we're saying the prop is non-null (which is true
because of the default value from getDefaultProps), Flow won't complain
about this.props.renderScrollView() needing a null check.


Reply to this email directly or view it on GitHub
https://github.com/facebook/react-native/pull/785/files#r32279234.

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, here's a small example:

/**
 * @flow
 */
'use strict';

var React = require('react-native');
var { PropTypes, Text } = React;

var App = React.createClass({
  propTypes: {
    getContent: PropTypes.func,
  },

  render() {
    var content = this.props.getContent();
    return <Text>{content}</Text>;
  },
});

Flow prints:

/Users/ide/test/index.js:15:19,41: call of method getContent
Function cannot be called on possibly undefined value
/Users/ide/test/index.js:11:17,30: undefined

Adding isRequired makes the error go away.

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh cool, maybe new flow goodness. But defining a default for the prop and
leaving it not isRequired doesn't make the error go away? cc @glevi
On Thu, Jun 11, 2015 at 8:48 PM James Ide notifications@github.com wrote:

In Libraries/CustomComponents/ListView/ListView.js
#785 (comment):

@@ -164,6 +164,13 @@ var ListView = React.createClass({
/
renderSectionHeader: PropTypes.func,
/
*

  • \* (props) => renderable
    
  • *
    
  • \* A function that returns the scroll view in which the list rows are
    
  • \* rendered. Defaults to returning a ScrollView with the given props.
    
  • */
    
  • renderScrollView: React.PropTypes.func.isRequired,

Yeah, here's a small example:

/** * @flow */'use strict';
var React = require('react-native');var { PropTypes, Text } = React;
var App = React.createClass({
propTypes: {
getContent: PropTypes.func,
},

render() {
var content = this.props.getContent();
return {content};
},
});

Flow prints:

/Users/ide/test/index.js:15:19,41: call of method getContent
Function cannot be called on possibly undefined value
/Users/ide/test/index.js:11:17,30: undefined

Adding isRequired makes the error go away.


Reply to this email directly or view it on GitHub
https://github.com/facebook/react-native/pull/785/files#r32288705.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Adding getDefaultProps doesn't make the error go away (Flow 0.11.0):

  getDefaultProps() {
    return {
      getContent() { return 'x'; }
    };
  },

@bogdantmm92
Copy link

Will this ever merge into the main repo?

@sahrens
Copy link
Contributor

sahrens commented Jun 23, 2015

Sorry, bit of a holdup but will get it out soon.

-Spencer

On Jun 22, 2015, at 3:06 PM, bogdantmm92 notifications@github.com wrote:

Will this ever merge into the main repo?


Reply to this email directly or view it on GitHub.

evansolomon added a commit to evansolomon/react-native that referenced this pull request Jun 24, 2015
evansolomon added a commit to evansolomon/react-native that referenced this pull request Jun 24, 2015
This enables code like:
```js
<ListView renderScrollView={(props) => <CustomScrollView {...props} />} />
```

where CustomScrollView might be inverted or support pull-to-refresh, etc.
evansolomon added a commit to evansolomon/react-native that referenced this pull request Jun 26, 2015
evansolomon added a commit to evansolomon/react-native that referenced this pull request Jun 26, 2015
evansolomon added a commit to evansolomon/react-native that referenced this pull request Jun 26, 2015
@brentvatne
Copy link
Collaborator

cc @sahrens - this would be nice to get into 0.8.0-rc :)

@ide
Copy link
Contributor Author

ide commented Jul 7, 2015

fwiw I'm doing some scroll view work right now and this pattern is working reasonably well in practice e.g. i can make a refreshable, infinitely scrolling list view.

@sahrens
Copy link
Contributor

sahrens commented Jul 8, 2015

Sorry, some tests were failing so this got derailed. I'll try to land soon since Animated is mostly done.

On Jul 7, 2015, at 11:35 PM, James Ide notifications@github.com wrote:

fwiw I'm doing some scroll view work right now and this pattern is working reasonably well in practice e.g. i can make a refreshable, infinitely scrolling list view.


Reply to this email directly or view it on GitHub.

@ide ide closed this in b3e0a70 Jul 9, 2015
@ide ide deleted the listview-composition branch July 10, 2015 02:17
Fanghao pushed a commit to discord/react-native that referenced this pull request Jul 22, 2015
Summary:
This enables code like:
```js
<ListView renderScrollView={() => <CustomScrollView />} />
```

where CustomScrollView might be inverted or support pull-to-refresh, etc.
Closes facebook#785
Github Author: James Ide <ide@jameside.com>
@paramaggarwal
Copy link
Contributor

Thanks for this @ide! Please do consider removing the isRequired if the Flow issues are fixed!

@ide
Copy link
Contributor Author

ide commented Aug 14, 2015

@paramaggarwal Can you send a PR if flow understands getDefaultProps now?

@paramaggarwal
Copy link
Contributor

@ide Oops! I thought you would know - I'm not very familiar with Flow. Sorry, ignore!

@alvaromb
Copy link
Contributor

alvaromb commented Nov 9, 2015

I'm getting the following warning when wrapping <ListView /> inside a component:

Warning: Failed propType: Required prop `renderScrollComponent` was not specified in `WrappedListViewComponent`. Check the render method of `Component`.

I'm just wrapping the list view to use a custom mixin.

import React, { ListView } from 'react-native'
import KeyboardAwareMixin from './KeyboardAwareMixin'

const KeyboardAwareListView = React.createClass({
  propTypes: {
    ...ListView.propTypes,
  },
  mixins: [KeyboardAwareMixin],

  render: function () {
    return (
      <ListView
        ref='keyboardView'
        keyboardDismissMode='interactive'
        contentInset={{bottom: this.state.keyboardSpace}}
        showsVerticalScrollIndicator={true}
        {...this.props}
      />
    )
  },
})

export default KeyboardAwareListView

Should I take a different approach or renderScrollComponent should't be required?

@ide
Copy link
Contributor Author

ide commented Nov 9, 2015

@alvaromb we could probably make the prop non-required. It was marked as required to tell the Flow type checker that the prop was always defined, but feel free to send a PR to mark it non-required, as long as the type checker passes.

acoates-ms pushed a commit to acoates-ms/react-native that referenced this pull request Aug 3, 2021
* Update RCTCxxBridge.mm

* Update RCTCxxBridge.mm

* nil check websocket URL

* use RCTAssertParam

Co-authored-by: Chris Hogan <chrishogan@Chriss-MacBook-Pro-2.local>
mganandraj pushed a commit to mganandraj/react-native that referenced this pull request Oct 28, 2021
* Add nullability checks (facebook#704)

* Update RCTCxxBridge.mm

* add nullability checks

* Check a nil URL to fix crashes connecting to socket (facebook#785)

* Update RCTCxxBridge.mm

* Update RCTCxxBridge.mm

* nil check websocket URL

* use RCTAssertParam

Co-authored-by: Chris Hogan <chrishogan@Chriss-MacBook-Pro-2.local>

* pod install

Co-authored-by: Chris Hogan <chrishogan@Chriss-MacBook-Pro-2.local>
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.

10 participants