mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Merge pull request #2537 from sebmarkbage/hidedomcomponentinternals
Wrap every DOM node in a Composite Component
This commit is contained in:
@@ -15,7 +15,6 @@
|
||||
|
||||
var React = require('React');
|
||||
var ReactDOM = require('ReactDOM');
|
||||
var ReactMount = require('ReactMount');
|
||||
var ReactTestUtils = require('ReactTestUtils');
|
||||
var div = React.createFactory('div');
|
||||
|
||||
@@ -53,7 +52,7 @@ describe('ReactDOM', function() {
|
||||
var argDiv = ReactTestUtils.renderIntoDocument(
|
||||
div(null, 'child')
|
||||
);
|
||||
var argNode = ReactMount.getNode(argDiv._rootNodeID);
|
||||
var argNode = argDiv.getDOMNode();
|
||||
expect(argNode.innerHTML).toBe('child');
|
||||
});
|
||||
|
||||
@@ -61,7 +60,7 @@ describe('ReactDOM', function() {
|
||||
var conflictDiv = ReactTestUtils.renderIntoDocument(
|
||||
div({children: 'fakechild'}, 'child')
|
||||
);
|
||||
var conflictNode = ReactMount.getNode(conflictDiv._rootNodeID);
|
||||
var conflictNode = conflictDiv.getDOMNode();
|
||||
expect(conflictNode.innerHTML).toBe('child');
|
||||
});
|
||||
|
||||
@@ -103,7 +102,7 @@ describe('ReactDOM', function() {
|
||||
theBird: <div className="bird" />
|
||||
}
|
||||
});
|
||||
var root = ReactMount.getNode(myDiv._rootNodeID);
|
||||
var root = myDiv.getDOMNode();
|
||||
var dog = root.childNodes[0];
|
||||
expect(dog.className).toBe('bigdog');
|
||||
});
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
var CSSPropertyOperations = require('CSSPropertyOperations');
|
||||
var DOMProperty = require('DOMProperty');
|
||||
var DOMPropertyOperations = require('DOMPropertyOperations');
|
||||
var ReactBrowserComponentMixin = require('ReactBrowserComponentMixin');
|
||||
var ReactComponent = require('ReactComponent');
|
||||
var ReactBrowserEventEmitter = require('ReactBrowserEventEmitter');
|
||||
var ReactMount = require('ReactMount');
|
||||
@@ -148,7 +147,6 @@ function validateDangerousTag(tag) {
|
||||
function ReactDOMComponent(tag) {
|
||||
validateDangerousTag(tag);
|
||||
this._tag = tag;
|
||||
this.tagName = tag.toUpperCase();
|
||||
}
|
||||
|
||||
ReactDOMComponent.displayName = 'ReactDOMComponent';
|
||||
@@ -488,8 +486,7 @@ assign(
|
||||
ReactDOMComponent.prototype,
|
||||
ReactComponent.Mixin,
|
||||
ReactDOMComponent.Mixin,
|
||||
ReactMultiChild.Mixin,
|
||||
ReactBrowserComponentMixin
|
||||
ReactMultiChild.Mixin
|
||||
);
|
||||
|
||||
module.exports = ReactDOMComponent;
|
||||
|
||||
@@ -135,13 +135,7 @@ function getNode(id) {
|
||||
* @internal
|
||||
*/
|
||||
function getNodeFromInstance(instance) {
|
||||
// This instance can currently be either a public or private instance since
|
||||
// native nodes are still public.
|
||||
var id = instance._rootNodeID;
|
||||
// TODO: Once these are only public instances, remove this conditional.
|
||||
if (id == null) {
|
||||
id = ReactInstanceMap.get(instance)._rootNodeID;
|
||||
}
|
||||
var id = ReactInstanceMap.get(instance)._rootNodeID;
|
||||
if (ReactEmptyComponent.isNullComponentID(id)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ var mouseListenerNames = keyMirror({
|
||||
*/
|
||||
var ReactDOMButton = ReactClass.createClass({
|
||||
displayName: 'ReactDOMButton',
|
||||
tagName: 'BUTTON',
|
||||
|
||||
mixins: [AutoFocusMixin, ReactBrowserComponentMixin],
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ var form = ReactElement.createFactory('form');
|
||||
*/
|
||||
var ReactDOMForm = ReactClass.createClass({
|
||||
displayName: 'ReactDOMForm',
|
||||
tagName: 'FORM',
|
||||
|
||||
mixins: [ReactBrowserComponentMixin, LocalEventTrapMixin],
|
||||
|
||||
|
||||
@@ -52,6 +52,7 @@ function forceUpdateIfMounted() {
|
||||
*/
|
||||
var ReactDOMInput = ReactClass.createClass({
|
||||
displayName: 'ReactDOMInput',
|
||||
tagName: 'INPUT',
|
||||
|
||||
mixins: [AutoFocusMixin, LinkedValueUtils.Mixin, ReactBrowserComponentMixin],
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ var option = ReactElement.createFactory('option');
|
||||
*/
|
||||
var ReactDOMOption = ReactClass.createClass({
|
||||
displayName: 'ReactDOMOption',
|
||||
tagName: 'OPTION',
|
||||
|
||||
mixins: [ReactBrowserComponentMixin],
|
||||
|
||||
|
||||
@@ -109,6 +109,7 @@ function updateOptions(component, propValue) {
|
||||
*/
|
||||
var ReactDOMSelect = ReactClass.createClass({
|
||||
displayName: 'ReactDOMSelect',
|
||||
tagName: 'SELECT',
|
||||
|
||||
mixins: [AutoFocusMixin, LinkedValueUtils.Mixin, ReactBrowserComponentMixin],
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@ function forceUpdateIfMounted() {
|
||||
*/
|
||||
var ReactDOMTextarea = ReactClass.createClass({
|
||||
displayName: 'ReactDOMTextarea',
|
||||
tagName: 'TEXTAREA',
|
||||
|
||||
mixins: [AutoFocusMixin, LinkedValueUtils.Mixin, ReactBrowserComponentMixin],
|
||||
|
||||
|
||||
@@ -453,7 +453,11 @@ var ReactComponent = {
|
||||
* @internal
|
||||
*/
|
||||
getPublicInstance: function() {
|
||||
return this;
|
||||
invariant(
|
||||
false,
|
||||
'getPublicInstance should never be called on the base class. It must ' +
|
||||
'be overriden.'
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -11,6 +11,9 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
var ReactClass = require('ReactClass');
|
||||
var ReactElement = require('ReactElement');
|
||||
|
||||
var assign = require('Object.assign');
|
||||
var invariant = require('invariant');
|
||||
|
||||
@@ -37,6 +40,22 @@ var ReactNativeComponentInjection = {
|
||||
}
|
||||
};
|
||||
|
||||
function autoGenerateWrapperClass(type) {
|
||||
return ReactClass.createClass({
|
||||
tagName: type.toUpperCase(),
|
||||
render: function() {
|
||||
return new ReactElement(
|
||||
type,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
this.props
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an internal class for a specific tag.
|
||||
*
|
||||
@@ -47,12 +66,7 @@ var ReactNativeComponentInjection = {
|
||||
function createInstanceForTag(tag, props, parentType) {
|
||||
var componentClass = tagToComponentClass[tag];
|
||||
if (componentClass == null) {
|
||||
invariant(
|
||||
genericComponentClass,
|
||||
'There is no registered component for the tag %s',
|
||||
tag
|
||||
);
|
||||
return new genericComponentClass(tag, props);
|
||||
tagToComponentClass[tag] = componentClass = autoGenerateWrapperClass(tag);
|
||||
}
|
||||
if (parentType === tag) {
|
||||
// Avoid recursion
|
||||
|
||||
@@ -26,10 +26,6 @@ describe('ReactComponent', function() {
|
||||
reactComponentExpect = require('reactComponentExpect');
|
||||
|
||||
getMountDepth = function(instance) {
|
||||
if (instance.mountComponent) {
|
||||
// Native instance
|
||||
return instance._mountDepth;
|
||||
}
|
||||
return ReactInstanceMap.get(instance)._mountDepth;
|
||||
};
|
||||
});
|
||||
@@ -306,9 +302,9 @@ describe('ReactComponent', function() {
|
||||
expect(getMountDepth(root)).toBe(0);
|
||||
expect(getMountDepth(root.refs.switcher)).toBe(1);
|
||||
expect(getMountDepth(root.refs.switcher.refs.box)).toBe(2);
|
||||
expect(getMountDepth(root.refs.switcher.refs.switcherDiv)).toBe(4);
|
||||
expect(getMountDepth(root.refs.child)).toBe(5);
|
||||
expect(getMountDepth(root.refs.switcher.refs.switcherDiv)).toBe(5);
|
||||
expect(getMountDepth(root.refs.child)).toBe(7);
|
||||
expect(getMountDepth(root.refs.switcher.refs.box.refs.boxDiv)).toBe(3);
|
||||
expect(getMountDepth(root.refs.child.refs.span)).toBe(6);
|
||||
expect(getMountDepth(root.refs.child.refs.span)).toBe(8);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -66,8 +66,8 @@ describe('ReactCompositeComponent', function() {
|
||||
* reallocated again.
|
||||
*/
|
||||
ChildUpdates = React.createClass({
|
||||
getAnchorID: function() {
|
||||
return this.refs.anch._rootNodeID;
|
||||
getAnchor: function() {
|
||||
return this.refs.anch;
|
||||
},
|
||||
render: function() {
|
||||
var className = cx({'anchorClass': this.props.anchorClassOn});
|
||||
@@ -182,8 +182,8 @@ describe('ReactCompositeComponent', function() {
|
||||
instance.setProps({renderAnchor: false}); // Clear out the anchor
|
||||
// rerender
|
||||
instance.setProps({renderAnchor: true, anchorClassOn: false});
|
||||
var anchorID = instance.getAnchorID();
|
||||
var actualDOMAnchorNode = ReactMount.getNode(anchorID);
|
||||
var anchor = instance.getAnchor();
|
||||
var actualDOMAnchorNode = anchor.getDOMNode();
|
||||
expect(actualDOMAnchorNode.className).toBe('');
|
||||
});
|
||||
|
||||
@@ -779,9 +779,11 @@ describe('ReactCompositeComponent', function() {
|
||||
React.unmountComponentAtNode(container);
|
||||
expect(innerUnmounted).toBe(true);
|
||||
|
||||
// <Component />, <Inner />, and both <div /> elements each call
|
||||
// unmountIDFromEnvironment which calls purgeID, for a total of 4.
|
||||
expect(ReactMount.purgeID.callCount).toBe(4);
|
||||
// <Component />, <Inner />, and both <div /> elements and their wrappers
|
||||
// each call unmountIDFromEnvironment which calls purgeID, for a total of 6.
|
||||
// TODO: Test the effect of this. E.g. does the node cache get repopulated
|
||||
// after a getDOMNode call?
|
||||
expect(ReactMount.purgeID.callCount).toBe(6);
|
||||
});
|
||||
|
||||
it('should warn when shouldComponentUpdate() returns undefined', function() {
|
||||
|
||||
@@ -26,8 +26,8 @@ describe('ReactCompositeComponent-error', function() {
|
||||
}
|
||||
});
|
||||
|
||||
var instance = <Component />;
|
||||
instance = ReactTestUtils.renderIntoDocument(instance);
|
||||
new Component();
|
||||
|
||||
expect(ReactErrorUtils.guard.mostRecentCall.args[1])
|
||||
.toEqual('Component.someHandler');
|
||||
});
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
"use strict";
|
||||
|
||||
var React = require('React');
|
||||
var ReactInstanceMap = require('ReactInstanceMap');
|
||||
var ReactTestUtils = require('ReactTestUtils');
|
||||
var ReactMount = require('ReactMount');
|
||||
|
||||
@@ -66,8 +67,7 @@ describe('ReactInstanceHandles', function() {
|
||||
if (instance === null) {
|
||||
return '';
|
||||
}
|
||||
var internal = ReactTestUtils.getInternalRepresentation(instance);
|
||||
return internal._rootNodeID;
|
||||
return ReactInstanceMap.get(instance)._rootNodeID;
|
||||
}
|
||||
|
||||
beforeEach(function() {
|
||||
|
||||
@@ -87,7 +87,10 @@ var FriendsStatusDisplay = React.createClass({
|
||||
// TODO: Update this to a better test that doesn't rely so much on internal
|
||||
// implementation details.
|
||||
var statusDisplays =
|
||||
ReactInstanceMap.get(this)._renderedComponent._renderedChildren;
|
||||
ReactInstanceMap.get(this)
|
||||
._renderedComponent
|
||||
._renderedComponent
|
||||
._renderedChildren;
|
||||
for (name in statusDisplays) {
|
||||
var child = statusDisplays[name];
|
||||
var isPresent = !!child;
|
||||
|
||||
@@ -99,14 +99,6 @@ var ReactTestUtils = {
|
||||
(inst.constructor === type));
|
||||
},
|
||||
|
||||
getInternalRepresentation: function(inst) {
|
||||
// TODO: Remove this duck check once we have a separate DOM/Native instance
|
||||
if (typeof inst.mountComponent === 'function') {
|
||||
return inst;
|
||||
}
|
||||
return ReactInstanceMap.get(inst);
|
||||
},
|
||||
|
||||
getRenderedChildOfCompositeComponent: function(inst) {
|
||||
if (!ReactTestUtils.isCompositeComponent(inst)) {
|
||||
return null;
|
||||
@@ -121,7 +113,10 @@ var ReactTestUtils = {
|
||||
}
|
||||
var ret = test(inst) ? [inst] : [];
|
||||
if (ReactTestUtils.isDOMComponent(inst)) {
|
||||
var renderedChildren = inst._renderedChildren;
|
||||
var internalInstance = ReactInstanceMap.get(inst);
|
||||
var renderedChildren = internalInstance
|
||||
._renderedComponent
|
||||
._renderedChildren;
|
||||
var key;
|
||||
for (key in renderedChildren) {
|
||||
if (!renderedChildren.hasOwnProperty(key)) {
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
var ReactInstanceMap = require('ReactInstanceMap');
|
||||
var ReactTestUtils = require('ReactTestUtils');
|
||||
|
||||
var assign = require('Object.assign');
|
||||
@@ -27,14 +28,20 @@ function reactComponentExpect(instance) {
|
||||
|
||||
expect(instance).not.toBeNull();
|
||||
|
||||
this._instance = ReactTestUtils.getInternalRepresentation(instance);
|
||||
var internalInstance = ReactInstanceMap.get(instance);
|
||||
|
||||
expect(typeof instance).toBe('object');
|
||||
expect(typeof instance.constructor).toBe('function');
|
||||
expect(ReactTestUtils.isElement(instance)).toBe(false);
|
||||
expect(typeof internalInstance).toBe('object');
|
||||
expect(typeof internalInstance.constructor).toBe('function');
|
||||
expect(ReactTestUtils.isElement(internalInstance)).toBe(false);
|
||||
|
||||
return new reactComponentExpectInternal(internalInstance);
|
||||
}
|
||||
|
||||
assign(reactComponentExpect.prototype, {
|
||||
function reactComponentExpectInternal(internalInstance) {
|
||||
this._instance = internalInstance;
|
||||
}
|
||||
|
||||
assign(reactComponentExpectInternal.prototype, {
|
||||
// Getters -------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
@@ -62,7 +69,7 @@ assign(reactComponentExpect.prototype, {
|
||||
this.toBeCompositeComponent();
|
||||
var child = this._instance._renderedComponent;
|
||||
// TODO: Hide ReactEmptyComponent instances here?
|
||||
return new reactComponentExpect(child);
|
||||
return new reactComponentExpectInternal(child);
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -72,14 +79,15 @@ assign(reactComponentExpect.prototype, {
|
||||
// Currently only dom components have arrays of children, but that will
|
||||
// change soon.
|
||||
this.toBeDOMComponent();
|
||||
var renderedChildren = this._instance._renderedChildren || {};
|
||||
var renderedChildren =
|
||||
this._instance._renderedComponent._renderedChildren || {};
|
||||
for (var name in renderedChildren) {
|
||||
if (!renderedChildren.hasOwnProperty(name)) {
|
||||
continue;
|
||||
}
|
||||
if (renderedChildren[name]) {
|
||||
if (renderedChildren[name]._mountIndex === childIndex) {
|
||||
return new reactComponentExpect(renderedChildren[name]);
|
||||
return new reactComponentExpectInternal(renderedChildren[name]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -88,15 +96,16 @@ assign(reactComponentExpect.prototype, {
|
||||
|
||||
toBeDOMComponentWithChildCount: function(n) {
|
||||
this.toBeDOMComponent();
|
||||
expect(this._instance._renderedChildren).toBeTruthy();
|
||||
var len = Object.keys(this._instance._renderedChildren).length;
|
||||
expect(this._instance._renderedComponent._renderedChildren).toBeTruthy();
|
||||
var len = Object.keys(this._instance._renderedComponent._renderedChildren)
|
||||
.length;
|
||||
expect(len).toBe(n);
|
||||
return this;
|
||||
},
|
||||
|
||||
toBeDOMComponentWithNoChildren: function() {
|
||||
this.toBeDOMComponent();
|
||||
expect(this._instance._renderedChildren).toBeFalsy();
|
||||
expect(this._instance._renderedComponent._renderedChildren).toBeFalsy();
|
||||
return this;
|
||||
},
|
||||
|
||||
|
||||
Reference in New Issue
Block a user