[ShallowRenderer] Queue/rerender on dispatched action after render component with hooks (#14802)
* [shallow-renderer] Rerender on dispatched action out of render
Rodrigo Ribeiro committed
Feb 13, 2019 at 12:59 UTC
6d4038f0a638d82e9e528f02cc5a86afb410cf11
2 files changed
+39
-3
packages/react-test-renderer/src/ReactShallowRenderer.js
+6
-3
@@ -384,7 +384,7 @@ class ReactShallowRenderer {
384
'an infinite loop.',
385
);
386
387
- if (componentIdentity === this._currentlyRenderingComponent) {
387
+ if (componentIdentity === this._previousComponentIdentity) {
388
// This is a render phase update. Stash it in a lazily-created map of
389
// queue -> linked list of updates. After this render pass, we'll restart
390
// and apply the stashed updates on top of the work-in-progress hook.
@@ -408,10 +408,13 @@ class ReactShallowRenderer {
408
}
409
lastRenderPhaseUpdate.next = update;
410
}
411
+
412
+ if (!this._rendering) {
413
+ this.render(this._element, this._context);
414
+ }
415
} else {
416
// This means an update has happened after the function component has
413
- // returned. On the server this is a no-op. In React Fiber, the update
414
- // would be scheduled for a future render.
417
+ // returned from a different component.
418
}
419
}
420
packages/react-test-renderer/src/__tests__/ReactShallowRendererHooks-test.js
+33
@@ -90,6 +90,39 @@ describe('ReactShallowRenderer with hooks', () => {
90
);
91
});
92
93
+ it('should work with updating a value from useState outside the render', () => {
94
+ function SomeComponent({defaultName}) {
95
+ const [name, updateName] = React.useState(defaultName);
96
+
97
+ return (
98
+ <div onClick={() => updateName('Dan')}>
99
+ <p>
100
+ Your name is: <span>{name}</span>
101
+ </p>
102
+ </div>
103
+ );
104
+ }
105
+
106
+ const shallowRenderer = createRenderer();
107
+ const element = <SomeComponent defaultName={'Dominic'} />;
108
+ const result = shallowRenderer.render(element);
109
+
110
+ expect(result.props.children).toEqual(
111
+ <p>
112
+ Your name is: <span>Dominic</span>
113
+ </p>,
114
+ );
115
+
116
+ result.props.onClick();
117
+ const updated = shallowRenderer.render(element);
118
+
119
+ expect(updated.props.children).toEqual(
120
+ <p>
121
+ Your name is: <span>Dan</span>
122
+ </p>,
123
+ );
124
+ });
125
+
126
it('should work with useReducer', () => {
127
function reducer(state, action) {
128
switch (action.type) {