mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Merge pull request #3640 from jsfb/render-subtree-pass-context
Provide top level method for rendering subtree (passes context)
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* Copyright 2013-2015, 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.
|
||||
*
|
||||
* @emails react-core
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var React = require('React');
|
||||
var ReactTestUtils = require('ReactTestUtils');
|
||||
var renderSubtreeIntoContainer = require('renderSubtreeIntoContainer');
|
||||
|
||||
describe('renderSubtreeIntoContainer', function() {
|
||||
|
||||
it('should pass context when rendering subtree elsewhere', function () {
|
||||
|
||||
var portal = document.createElement('div');
|
||||
|
||||
var Component = React.createClass({
|
||||
contextTypes: {
|
||||
foo: React.PropTypes.string.isRequired
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return <div>{this.context.foo}</div>;
|
||||
}
|
||||
});
|
||||
|
||||
var Parent = React.createClass({
|
||||
childContextTypes: {
|
||||
foo: React.PropTypes.string.isRequired,
|
||||
},
|
||||
|
||||
getChildContext: function() {
|
||||
return {
|
||||
foo: 'bar'
|
||||
};
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return null;
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
expect(function() {
|
||||
renderSubtreeIntoContainer(this, <Component />, portal);
|
||||
}.bind(this)).not.toThrow();
|
||||
}
|
||||
});
|
||||
|
||||
ReactTestUtils.renderIntoDocument(<Parent />);
|
||||
expect(portal.firstChild.innerHTML).toBe('bar');
|
||||
});
|
||||
|
||||
it('should throw if parentComponent is invalid', function () {
|
||||
var portal = document.createElement('div');
|
||||
|
||||
var Component = React.createClass({
|
||||
contextTypes: {
|
||||
foo: React.PropTypes.string.isRequired
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return <div>{this.context.foo}</div>;
|
||||
}
|
||||
});
|
||||
|
||||
var Parent = React.createClass({
|
||||
childContextTypes: {
|
||||
foo: React.PropTypes.string.isRequired,
|
||||
},
|
||||
|
||||
getChildContext: function() {
|
||||
return {
|
||||
foo: 'bar'
|
||||
};
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return null;
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
expect(function() {
|
||||
renderSubtreeIntoContainer(<Parent />, <Component />, portal);
|
||||
}).toThrow('Invariant Violation: parentComponent' +
|
||||
'must be a valid React Component');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* Copyright 2013-2015, 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 renderSubtreeIntoContainer
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var ReactMount = require('ReactMount');
|
||||
|
||||
module.exports = ReactMount.renderSubtreeIntoContainer;
|
||||
@@ -28,6 +28,7 @@ var ReactTransitionGroup = require('ReactTransitionGroup');
|
||||
var ReactUpdates = require('ReactUpdates');
|
||||
|
||||
var cloneWithProps = require('cloneWithProps');
|
||||
var renderSubtreeIntoContainer = require('renderSubtreeIntoContainer');
|
||||
var shallowCompare = require('shallowCompare');
|
||||
var update = require('update');
|
||||
|
||||
@@ -40,6 +41,7 @@ React.addons = {
|
||||
batchedUpdates: ReactUpdates.batchedUpdates,
|
||||
cloneWithProps: cloneWithProps,
|
||||
createFragment: ReactFragment.create,
|
||||
renderSubtreeIntoContainer: renderSubtreeIntoContainer,
|
||||
shallowCompare: shallowCompare,
|
||||
update: update
|
||||
};
|
||||
|
||||
@@ -262,10 +262,12 @@ function mountComponentIntoNode(
|
||||
rootID,
|
||||
container,
|
||||
transaction,
|
||||
shouldReuseMarkup) {
|
||||
var context = emptyObject;
|
||||
shouldReuseMarkup,
|
||||
context) {
|
||||
if (__DEV__) {
|
||||
context = {};
|
||||
if (context === emptyObject) {
|
||||
context = {};
|
||||
}
|
||||
context[validateDOMNesting.tagStackContextKey] =
|
||||
[container.nodeName.toLowerCase()];
|
||||
}
|
||||
@@ -288,7 +290,8 @@ function batchedMountComponentIntoNode(
|
||||
componentInstance,
|
||||
rootID,
|
||||
container,
|
||||
shouldReuseMarkup) {
|
||||
shouldReuseMarkup,
|
||||
context) {
|
||||
var transaction = ReactUpdates.ReactReconcileTransaction.getPooled();
|
||||
transaction.perform(
|
||||
mountComponentIntoNode,
|
||||
@@ -297,7 +300,8 @@ function batchedMountComponentIntoNode(
|
||||
rootID,
|
||||
container,
|
||||
transaction,
|
||||
shouldReuseMarkup
|
||||
shouldReuseMarkup,
|
||||
context
|
||||
);
|
||||
ReactUpdates.ReactReconcileTransaction.release(transaction);
|
||||
}
|
||||
@@ -402,7 +406,8 @@ var ReactMount = {
|
||||
_renderNewRootComponent: function(
|
||||
nextElement,
|
||||
container,
|
||||
shouldReuseMarkup
|
||||
shouldReuseMarkup,
|
||||
context
|
||||
) {
|
||||
// Various parts of our code (such as ReactCompositeComponent's
|
||||
// _renderValidatedComponent) assume that calls to render aren't nested;
|
||||
@@ -432,7 +437,8 @@ var ReactMount = {
|
||||
componentInstance,
|
||||
reactRootID,
|
||||
container,
|
||||
shouldReuseMarkup
|
||||
shouldReuseMarkup,
|
||||
context
|
||||
);
|
||||
|
||||
if (__DEV__) {
|
||||
@@ -451,12 +457,26 @@ var ReactMount = {
|
||||
* perform an update on it and only mutate the DOM as necessary to reflect the
|
||||
* latest React component.
|
||||
*
|
||||
* @param {ReactComponent} parentComponent The conceptual parent of this render tree.
|
||||
* @param {ReactElement} nextElement Component element to render.
|
||||
* @param {DOMElement} container DOM element to render into.
|
||||
* @param {?function} callback function triggered on completion
|
||||
* @return {ReactComponent} Component instance rendered in `container`.
|
||||
*/
|
||||
render: function(nextElement, container, callback) {
|
||||
renderSubtreeIntoContainer: function(parentComponent, nextElement, container, callback) {
|
||||
invariant(
|
||||
parentComponent != null && parentComponent._reactInternalInstance != null,
|
||||
'parentComponent must be a valid React Component'
|
||||
);
|
||||
return ReactMount._renderSubtreeIntoContainer(
|
||||
parentComponent,
|
||||
nextElement,
|
||||
container,
|
||||
callback
|
||||
);
|
||||
},
|
||||
|
||||
_renderSubtreeIntoContainer: function(parentComponent, nextElement, container, callback) {
|
||||
invariant(
|
||||
ReactElement.isValidElement(nextElement),
|
||||
'React.render(): Invalid component element.%s',
|
||||
@@ -524,11 +544,15 @@ var ReactMount = {
|
||||
}
|
||||
|
||||
var shouldReuseMarkup = containerHasReactMarkup && !prevComponent;
|
||||
|
||||
var component = ReactMount._renderNewRootComponent(
|
||||
nextElement,
|
||||
container,
|
||||
shouldReuseMarkup
|
||||
shouldReuseMarkup,
|
||||
parentComponent != null ?
|
||||
parentComponent._reactInternalInstance._processChildContext(
|
||||
parentComponent._reactInternalInstance._context
|
||||
) :
|
||||
emptyObject
|
||||
).getPublicInstance();
|
||||
if (callback) {
|
||||
callback.call(component);
|
||||
@@ -536,6 +560,23 @@ var ReactMount = {
|
||||
return component;
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Renders a React component into the DOM in the supplied `container`.
|
||||
*
|
||||
* If the React component was previously rendered into `container`, this will
|
||||
* perform an update on it and only mutate the DOM as necessary to reflect the
|
||||
* latest React component.
|
||||
*
|
||||
* @param {ReactElement} nextElement Component element to render.
|
||||
* @param {DOMElement} container DOM element to render into.
|
||||
* @param {?function} callback function triggered on completion
|
||||
* @return {ReactComponent} Component instance rendered in `container`.
|
||||
*/
|
||||
render: function(nextElement, container, callback) {
|
||||
return ReactMount._renderSubtreeIntoContainer(null, nextElement, container, callback);
|
||||
},
|
||||
|
||||
/**
|
||||
* Constructs a component instance of `constructor` with `initialProps` and
|
||||
* renders it into the supplied `container`.
|
||||
|
||||
@@ -54,16 +54,16 @@ var ReactDefaultBatchingStrategy = {
|
||||
* Call the provided function in a context within which calls to `setState`
|
||||
* and friends are batched such that components aren't updated unnecessarily.
|
||||
*/
|
||||
batchedUpdates: function(callback, a, b, c, d) {
|
||||
batchedUpdates: function(callback, a, b, c, d, e) {
|
||||
var alreadyBatchingUpdates = ReactDefaultBatchingStrategy.isBatchingUpdates;
|
||||
|
||||
ReactDefaultBatchingStrategy.isBatchingUpdates = true;
|
||||
|
||||
// The code is written this way to avoid extra allocations
|
||||
if (alreadyBatchingUpdates) {
|
||||
callback(a, b, c, d);
|
||||
callback(a, b, c, d, e);
|
||||
} else {
|
||||
transaction.perform(callback, null, a, b, c, d);
|
||||
transaction.perform(callback, null, a, b, c, d, e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -105,9 +105,9 @@ assign(
|
||||
|
||||
PooledClass.addPoolingTo(ReactUpdatesFlushTransaction);
|
||||
|
||||
function batchedUpdates(callback, a, b, c, d) {
|
||||
function batchedUpdates(callback, a, b, c, d, e) {
|
||||
ensureInjected();
|
||||
batchingStrategy.batchedUpdates(callback, a, b, c, d);
|
||||
batchingStrategy.batchedUpdates(callback, a, b, c, d, e);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user