Skip to content

Commit eadbf33

Browse files
sophiebitszpao
authored andcommitted
Merge pull request facebook#5237 from spicyj/facebookgh-5125
Make sure top-level callback has correct context (cherry picked from commit b0a7a00)
1 parent 12cafa7 commit eadbf33

File tree

2 files changed

+103
-3
lines changed

2 files changed

+103
-3
lines changed

src/renderers/dom/client/ReactMount.js

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -635,12 +635,17 @@ var ReactMount = {
635635
var prevWrappedElement = prevComponent._currentElement;
636636
var prevElement = prevWrappedElement.props;
637637
if (shouldUpdateReactComponent(prevElement, nextElement)) {
638-
return ReactMount._updateRootComponent(
638+
var publicInst = prevComponent._renderedComponent.getPublicInstance();
639+
var updatedCallback = callback && function() {
640+
callback.call(publicInst);
641+
};
642+
ReactMount._updateRootComponent(
639643
prevComponent,
640644
nextWrappedElement,
641645
container,
642-
callback
643-
)._renderedComponent.getPublicInstance();
646+
updatedCallback
647+
);
648+
return publicInst;
644649
} else {
645650
ReactMount.unmountComponentAtNode(container);
646651
}

src/renderers/dom/client/__tests__/ReactMount-test.js

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,4 +245,99 @@ describe('ReactMount', function() {
245245
'render the new components instead of calling ReactDOM.render.'
246246
);
247247
});
248+
249+
it('should not crash in node cache when unmounting', function() {
250+
var Component = React.createClass({
251+
render: function() {
252+
// Add refs to some nodes so that they get traversed and cached
253+
return (
254+
<div ref="a">
255+
<div ref="b">b</div>
256+
{this.props.showC && <div>c</div>}
257+
</div>
258+
);
259+
},
260+
});
261+
262+
var container = document.createElement('container');
263+
264+
ReactDOM.render(<div><Component showC={false} /></div>, container);
265+
266+
// Right now, A and B are in the cache. When we add C, it won't get added to
267+
// the cache (assuming markup-string mode).
268+
ReactDOM.render(<div><Component showC={true} /></div>, container);
269+
270+
// Remove A, B, and C. Unmounting C shouldn't cause B to get recached.
271+
ReactDOM.render(<div></div>, container);
272+
273+
// Add them back -- this shouldn't cause a cached node collision.
274+
ReactDOM.render(<div><Component showC={true} /></div>, container);
275+
276+
ReactDOM.unmountComponentAtNode(container);
277+
});
278+
279+
it('should not crash in node cache when unmounting, case 2', function() {
280+
var A = React.createClass({
281+
render: function() {
282+
return <a key={this.props.innerKey}>{this.props.innerKey}</a>;
283+
},
284+
});
285+
var Component = React.createClass({
286+
render: function() {
287+
return (
288+
<b>
289+
<i>{this.props.step === 1 && <q />}</i>
290+
{this.props.step === 1 && <A innerKey={this.props.step} />}
291+
</b>
292+
);
293+
},
294+
});
295+
296+
var container = document.createElement('container');
297+
298+
ReactDOM.render(<Component step={1} />, container);
299+
ReactDOM.render(<Component step={2} />, container);
300+
ReactDOM.render(<Component step={1} />, container);
301+
ReactMount.getID(container.querySelector('a'));
302+
});
303+
304+
it('passes the correct callback context', function() {
305+
var container = document.createElement('div');
306+
var calls = 0;
307+
308+
ReactDOM.render(<div />, container, function() {
309+
expect(this.nodeName).toBe('DIV');
310+
calls++;
311+
});
312+
313+
// Update, no type change
314+
ReactDOM.render(<div />, container, function() {
315+
expect(this.nodeName).toBe('DIV');
316+
calls++;
317+
});
318+
319+
// Update, type change
320+
ReactDOM.render(<span />, container, function() {
321+
expect(this.nodeName).toBe('SPAN');
322+
calls++;
323+
});
324+
325+
// Batched update, no type change
326+
ReactDOM.unstable_batchedUpdates(function() {
327+
ReactDOM.render(<span />, container, function() {
328+
expect(this.nodeName).toBe('SPAN');
329+
calls++;
330+
});
331+
});
332+
333+
// Batched update, type change
334+
ReactDOM.unstable_batchedUpdates(function() {
335+
ReactDOM.render(<article />, container, function() {
336+
expect(this.nodeName).toBe('ARTICLE');
337+
calls++;
338+
});
339+
});
340+
341+
expect(calls).toBe(5);
342+
});
248343
});

0 commit comments

Comments
 (0)