From 6e179fb7cd68c92f8abd94d381f85c41298c828c Mon Sep 17 00:00:00 2001 From: Spencer Ahrens Date: Wed, 13 May 2015 18:33:43 -0700 Subject: [PATCH] [ReactNative] introduce mountSafeCallback Summary: `mountSafeCallback` simply wraps a callback in an `isMounted()` check to prevent crashes when old callbacks are called on unmounted components. @public Test Plan: Added logging and made sure callbacks were getting called through `mountSafeCallback` and that things worked (e.g. photo viewer rotation etc). --- Libraries/ReactIOS/NativeMethodsMixin.js | 16 ++++++++++++---- Libraries/Utilities/mountSafeCallback.js | 23 +++++++++++++++++++++++ 2 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 Libraries/Utilities/mountSafeCallback.js diff --git a/Libraries/ReactIOS/NativeMethodsMixin.js b/Libraries/ReactIOS/NativeMethodsMixin.js index 1bbf30b06498c9..4bc99f56b224ce 100644 --- a/Libraries/ReactIOS/NativeMethodsMixin.js +++ b/Libraries/ReactIOS/NativeMethodsMixin.js @@ -20,6 +20,7 @@ var findNodeHandle = require('findNodeHandle'); var flattenStyle = require('flattenStyle'); var invariant = require('invariant'); var mergeFast = require('mergeFast'); +var mountSafeCallback = require('mountSafeCallback'); var precomputeStyle = require('precomputeStyle'); type MeasureOnSuccessCallback = ( @@ -52,7 +53,11 @@ var animationIDInvariant = function( var NativeMethodsMixin = { addAnimation: function(anim: number, callback?: (finished: bool) => void) { animationIDInvariant('addAnimation', anim); - RCTPOPAnimationManager.addAnimation(findNodeHandle(this), anim, callback); + RCTPOPAnimationManager.addAnimation( + findNodeHandle(this), + anim, + mountSafeCallback(this, callback) + ); }, removeAnimation: function(anim: number) { @@ -61,7 +66,10 @@ var NativeMethodsMixin = { }, measure: function(callback: MeasureOnSuccessCallback) { - RCTUIManager.measure(findNodeHandle(this), callback); + RCTUIManager.measure( + findNodeHandle(this), + mountSafeCallback(this, callback) + ); }, measureLayout: function( @@ -72,8 +80,8 @@ var NativeMethodsMixin = { RCTUIManager.measureLayout( findNodeHandle(this), relativeToNativeNode, - onFail, - onSuccess + mountSafeCallback(this, onFail), + mountSafeCallback(this, onSuccess) ); }, diff --git a/Libraries/Utilities/mountSafeCallback.js b/Libraries/Utilities/mountSafeCallback.js new file mode 100644 index 00000000000000..c065718d19a4d2 --- /dev/null +++ b/Libraries/Utilities/mountSafeCallback.js @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule mountSafeCallback + * @flow + */ +'use strict'; + +var mountSafeCallback = function(context: ReactComponent, callback: ?Function): any { + return function() { + if (!callback || !context.isMounted()) { + return; + } + return callback.apply(context, arguments); + }; +}; + +module.exports = mountSafeCallback;