From 6d4038f0a638d82e9e528f02cc5a86afb410cf11 Mon Sep 17 00:00:00 2001 From: Rodrigo Ribeiro Date: Wed, 13 Feb 2019 12:59:02 -0300 Subject: [PATCH] [ShallowRenderer] Queue/rerender on dispatched action after render component with hooks (#14802) * [shallow-renderer] Rerender on dispatched action out of render --- .../src/ReactShallowRenderer.js | 9 +++-- .../ReactShallowRendererHooks-test.js | 33 +++++++++++++++++++ 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/packages/react-test-renderer/src/ReactShallowRenderer.js b/packages/react-test-renderer/src/ReactShallowRenderer.js index 7472556c68954..06e3f0f99c2dc 100644 --- a/packages/react-test-renderer/src/ReactShallowRenderer.js +++ b/packages/react-test-renderer/src/ReactShallowRenderer.js @@ -384,7 +384,7 @@ class ReactShallowRenderer { 'an infinite loop.', ); - if (componentIdentity === this._currentlyRenderingComponent) { + if (componentIdentity === this._previousComponentIdentity) { // This is a render phase update. Stash it in a lazily-created map of // queue -> linked list of updates. After this render pass, we'll restart // and apply the stashed updates on top of the work-in-progress hook. @@ -408,10 +408,13 @@ class ReactShallowRenderer { } lastRenderPhaseUpdate.next = update; } + + if (!this._rendering) { + this.render(this._element, this._context); + } } else { // This means an update has happened after the function component has - // returned. On the server this is a no-op. In React Fiber, the update - // would be scheduled for a future render. + // returned from a different component. } } diff --git a/packages/react-test-renderer/src/__tests__/ReactShallowRendererHooks-test.js b/packages/react-test-renderer/src/__tests__/ReactShallowRendererHooks-test.js index da352a971e160..40327640e9617 100644 --- a/packages/react-test-renderer/src/__tests__/ReactShallowRendererHooks-test.js +++ b/packages/react-test-renderer/src/__tests__/ReactShallowRendererHooks-test.js @@ -90,6 +90,39 @@ describe('ReactShallowRenderer with hooks', () => { ); }); + it('should work with updating a value from useState outside the render', () => { + function SomeComponent({defaultName}) { + const [name, updateName] = React.useState(defaultName); + + return ( +
updateName('Dan')}> +

+ Your name is: {name} +

+
+ ); + } + + const shallowRenderer = createRenderer(); + const element = ; + const result = shallowRenderer.render(element); + + expect(result.props.children).toEqual( +

+ Your name is: Dominic +

, + ); + + result.props.onClick(); + const updated = shallowRenderer.render(element); + + expect(updated.props.children).toEqual( +

+ Your name is: Dan +

, + ); + }); + it('should work with useReducer', () => { function reducer(state, action) { switch (action.type) {