From 26479b0073bec4c53f8cfcfcb63729070d3e1dbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Voda?= Date: Sun, 22 Nov 2015 20:32:03 +0100 Subject: [PATCH] Catch errors from component's render() method to prevent getting into incosistent state --- .../reconciler/ReactCompositeComponent.js | 21 ++++++++++++++++++- .../__tests__/ReactCompositeComponent-test.js | 3 ++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/renderers/shared/reconciler/ReactCompositeComponent.js b/src/renderers/shared/reconciler/ReactCompositeComponent.js index b341eec2f8d37..7d159c7d69640 100644 --- a/src/renderers/shared/reconciler/ReactCompositeComponent.js +++ b/src/renderers/shared/reconciler/ReactCompositeComponent.js @@ -786,7 +786,26 @@ var ReactCompositeComponentMixin = { */ _renderValidatedComponentWithoutOwnerOrContext: function() { var inst = this._instance; - var renderedComponent = inst.render(); + + if (typeof inst.render !== 'function') { + throw new TypeError('render is not a function'); + } + + try { + var renderedComponent = inst.render(); + } catch (err) { + warning( + false, + '%s(...): The `render` method threw error. Empty element will ' + + 'be displayed instead.', + this.getName() || 'ReactCompositeComponent' + ); + setTimeout(function() { + throw err; + }, 0); + renderedComponent = null; + } + if (__DEV__) { // We allow auto-mocks to proceed as if they're returning null. if (typeof renderedComponent === 'undefined' && diff --git a/src/renderers/shared/reconciler/__tests__/ReactCompositeComponent-test.js b/src/renderers/shared/reconciler/__tests__/ReactCompositeComponent-test.js index 84fa9274ec381..1ce69c7b5b8e5 100644 --- a/src/renderers/shared/reconciler/__tests__/ReactCompositeComponent-test.js +++ b/src/renderers/shared/reconciler/__tests__/ReactCompositeComponent-test.js @@ -475,9 +475,10 @@ describe('ReactCompositeComponent', function() { expect(function() { instance = ReactTestUtils.renderIntoDocument(instance); - }).toThrow(); + }).not.toThrow(); expect(ReactCurrentOwner.current).toBe(null); + expect(console.error.calls.length).toBe(1); }); it('should call componentWillUnmount before unmounting', function() {