From eaba2abc0b76f9a26703c87eecf4a8bb52f9ed3e Mon Sep 17 00:00:00 2001 From: James Ide Date: Thu, 14 Apr 2016 06:40:54 -0700 Subject: [PATCH] Use function refs and support composed refs Summary:Fixes an issue where if you implement `renderScrollComponent` and have a `ref` callback on the returned element, the ref used to be clobbered by the ref that ListView adds to the element. This is accomplished by converting the ref from a legacy string-based ref to a callback-based ref, and then using `cloneReferencedElement`, which is a simple utility to compose callback refs. Closes https://github.com/facebook/react-native/pull/6441 Differential Revision: D3064250 Pulled By: mkonicek fb-gh-sync-id: 2d55d04e2144a1cc08900a57a1fc0dab07c87eea fbshipit-source-id: 2d55d04e2144a1cc08900a57a1fc0dab07c87eea --- .../CustomComponents/ListView/ListView.js | 33 ++++++++++--------- package.json | 1 + 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/Libraries/CustomComponents/ListView/ListView.js b/Libraries/CustomComponents/ListView/ListView.js index 9b2b0f803..8ad22cf93 100644 --- a/Libraries/CustomComponents/ListView/ListView.js +++ b/Libraries/CustomComponents/ListView/ListView.js @@ -40,6 +40,7 @@ var ScrollResponder = require('ScrollResponder'); var StaticRenderer = require('StaticRenderer'); var TimerMixin = require('react-timer-mixin'); +var cloneReferencedElement = require('react-clone-referenced-element'); var isEmpty = require('isEmpty'); var merge = require('merge'); @@ -50,7 +51,6 @@ var DEFAULT_INITIAL_ROWS = 10; var DEFAULT_SCROLL_RENDER_AHEAD = 1000; var DEFAULT_END_REACHED_THRESHOLD = 1000; var DEFAULT_SCROLL_CALLBACK_THROTTLE = 50; -var SCROLLVIEW_REF = 'listviewscroll'; /** @@ -243,13 +243,13 @@ var ListView = React.createClass({ /** * Provides a handle to the underlying scroll responder. - * Note that the view in `SCROLLVIEW_REF` may not be a `ScrollView`, so we + * Note that `this._scrollComponent` might not be a `ScrollView`, so we * need to check that it responds to `getScrollResponder` before calling it. */ getScrollResponder: function() { - return this.refs[SCROLLVIEW_REF] && - this.refs[SCROLLVIEW_REF].getScrollResponder && - this.refs[SCROLLVIEW_REF].getScrollResponder(); + if (this._scrollComponent && this._scrollComponent.getScrollResponder) { + return this._scrollComponent.getScrollResponder(); + } }, /** @@ -258,14 +258,15 @@ var ListView = React.createClass({ * See `ScrollView#scrollTo`. */ scrollTo: function(...args) { - this.refs[SCROLLVIEW_REF] && - this.refs[SCROLLVIEW_REF].scrollTo && - this.refs[SCROLLVIEW_REF].scrollTo(...args); + if (this._scrollComponent && this._scrollComponent.scrollTo) { + this._scrollComponent.scrollTo(...args); + } }, setNativeProps: function(props) { - this.refs[SCROLLVIEW_REF] && - this.refs[SCROLLVIEW_REF].setNativeProps(props); + if (this._scrollComponent) { + this._scrollComponent.setNativeProps(props); + } }, /** @@ -291,7 +292,7 @@ var ListView = React.createClass({ }, getInnerViewNode: function() { - return this.refs[SCROLLVIEW_REF].getInnerViewNode(); + return this._scrollComponent.getInnerViewNode(); }, componentWillMount: function() { @@ -459,10 +460,8 @@ var ListView = React.createClass({ onKeyboardDidHide: undefined, }); - // TODO(ide): Use function refs so we can compose with the scroll - // component's original ref instead of clobbering it - return React.cloneElement(renderScrollComponent(props), { - ref: SCROLLVIEW_REF, + return cloneReferencedElement(renderScrollComponent(props), { + ref: this._setScrollComponentRef, onContentSizeChange: this._onContentSizeChange, onLayout: this._onLayout, }, header, bodyComponents, footer); @@ -487,6 +486,10 @@ var ListView = React.createClass({ ); }, + _setScrollComponentRef: function(scrollComponent) { + this._scrollComponent = scrollComponent; + }, + _onContentSizeChange: function(width, height) { var contentLength = !this.props.horizontal ? height : width; if (contentLength !== this.scrollProperties.contentLength) { diff --git a/package.json b/package.json index c22df84cc..b70c6896d 100644 --- a/package.json +++ b/package.json @@ -163,6 +163,7 @@ "optimist": "^0.6.1", "progress": "^1.1.8", "promise": "^7.1.1", + "react-clone-referenced-element": "^1.0.1", "react-timer-mixin": "^0.13.2", "react-transform-hmr": "^1.0.4", "rebound": "^0.0.13",