RefreshControl refreshing prop and doc improvements

Summary:This makes the `refreshing` prop more 'controlled'. Before forgetting to set the refreshing prop in the onRefresh callback would make the js and native `refreshing` prop get out of sync and make the RefreshControl stop refreshing properly (see #5839).

I also added a simple usage example and a note about the refreshing prop in the doc.

There was also a small bug in the doc generation code that made the array of color show as [[object Object]] instead of [color] so I fixed that too.

** Test plan**
Tested using the UIExplorer example on iOS and Android. Not setting the `refreshing` prop to true in the `onRefresh` function should cause the RefreshControl to stop refreshing immediately and continue working properly after.

Closes #5839
Closes https://github.com/facebook/react-native/pull/6434

Differential Revision: D3046279

Pulled By: nicklockwood

fb-gh-sync-id: ebda04c659a10f0b9d468473c8d5c659256ca1b5
shipit-source-id: ebda04c659a10f0b9d468473c8d5c659256ca1b5
This commit is contained in:
Janic Duplessis 2016-03-13 03:03:22 -07:00 committed by Facebook Github Bot 7
parent 972395a7c9
commit 88ebdb2a65
2 changed files with 64 additions and 8 deletions

View File

@ -11,9 +11,10 @@
*/ */
'use strict'; 'use strict';
const React = require('React');
const Platform = require('Platform');
const ColorPropType = require('ColorPropType'); const ColorPropType = require('ColorPropType');
const NativeMethodsMixin = require('NativeMethodsMixin');
const Platform = require('Platform');
const React = require('React');
const View = require('View'); const View = require('View');
const requireNativeComponent = require('requireNativeComponent'); const requireNativeComponent = require('requireNativeComponent');
@ -25,15 +26,57 @@ if (Platform.OS === 'android') {
} }
/** /**
* This component is used inside a ScrollView to add pull to refresh * This component is used inside a ScrollView or ListView to add pull to refresh
* functionality. When the ScrollView is at `scrollY: 0`, swiping down * functionality. When the ScrollView is at `scrollY: 0`, swiping down
* triggers an `onRefresh` event. * triggers an `onRefresh` event.
*
* ### Usage example
*
* ``` js
* class RefreshableList extends Component {
* constructor(props) {
* super(props);
* this.state = {
* refreshing: false,
* };
* }
*
* _onRefresh() {
* this.setState({refreshing: true});
* fetchData().then(() => {
* this.setState({refreshing: false});
* });
* }
*
* render() {
* return (
* <ListView
* refreshControl={
* <RefreshControl
* refreshing={this.state.refreshing}
* onRefresh={this._onRefresh.bind(this)}
* />
* }
* ...
* >
* ...
* </ListView>
* );
* }
* ...
* }
* ```
*
* __Note:__ `refreshing` is a controlled prop, this is why it needs to be set to true
* in the `onRefresh` function otherwise the refresh indicator will stop immediatly.
*/ */
const RefreshControl = React.createClass({ const RefreshControl = React.createClass({
statics: { statics: {
SIZE: RefreshLayoutConsts.SIZE, SIZE: RefreshLayoutConsts.SIZE,
}, },
mixins: [NativeMethodsMixin],
propTypes: { propTypes: {
...View.propTypes, ...View.propTypes,
/** /**
@ -76,8 +119,21 @@ const RefreshControl = React.createClass({
size: React.PropTypes.oneOf(RefreshLayoutConsts.SIZE.DEFAULT, RefreshLayoutConsts.SIZE.LARGE), size: React.PropTypes.oneOf(RefreshLayoutConsts.SIZE.DEFAULT, RefreshLayoutConsts.SIZE.LARGE),
}, },
_nativeRef: {},
render() { render() {
return <NativeRefreshControl {...this.props} />; return (
<NativeRefreshControl
{...this.props}
ref={ref => this._nativeRef = ref}
onRefresh={this._onRefresh}
/>
);
},
_onRefresh() {
this.props.onRefresh && this.props.onRefresh();
this._nativeRef.setNativeProps({refreshing: this.props.refreshing});
}, },
}); });

View File

@ -41,12 +41,12 @@ function renderType(type) {
return '{' + Object.keys(type.value).map((key => key + ': ' + renderType(type.value[key]))).join(', ') + '}'; return '{' + Object.keys(type.value).map((key => key + ': ' + renderType(type.value[key]))).join(', ') + '}';
} }
if (type.name == 'union') { if (type.name === 'union') {
return type.value.map(renderType).join(', '); return type.value.map(renderType).join(', ');
} }
if (type.name === 'arrayOf') { if (type.name === 'arrayOf') {
return '[' + renderType(type.value) + ']'; return <span>[{renderType(type.value)}]</span>;
} }
if (type.name === 'instanceOf') { if (type.name === 'instanceOf') {
@ -56,10 +56,10 @@ function renderType(type) {
if (type.name === 'custom') { if (type.name === 'custom') {
if (styleReferencePattern.test(type.raw)) { if (styleReferencePattern.test(type.raw)) {
var name = type.raw.substring(0, type.raw.indexOf('.')); var name = type.raw.substring(0, type.raw.indexOf('.'));
return <a href={'docs/' + slugify(name) + '.html#style'}>{name}#style</a> return <a href={'docs/' + slugify(name) + '.html#style'}>{name}#style</a>;
} }
if (type.raw === 'ColorPropType') { if (type.raw === 'ColorPropType') {
return <a href={'docs/colors.html'}>color</a> return <a href={'docs/colors.html'}>color</a>;
} }
if (type.raw === 'EdgeInsetsPropType') { if (type.raw === 'EdgeInsetsPropType') {
return '{top: number, left: number, bottom: number, right: number}'; return '{top: number, left: number, bottom: number, right: number}';