DOM components as refs
Still missing: .props/.getDOMNode warnings.
Ben Alpert committed
Jun 15, 2015 at 19:16 UTC
ffd527f593c02b7e11ad4e912cfd1da549b0709e
12 files changed
+35
-155
src/isomorphic/classic/element/ReactElementValidator.js
+2
-11
@@ -23,7 +23,6 @@ var ReactFragment = require('ReactFragment');
23
var ReactPropTypeLocations = require('ReactPropTypeLocations');
24
var ReactPropTypeLocationNames = require('ReactPropTypeLocationNames');
25
var ReactCurrentOwner = require('ReactCurrentOwner');
26
-var ReactNativeComponent = require('ReactNativeComponent');
26
27
var getIteratorFn = require('getIteratorFn');
28
var invariant = require('invariant');
@@ -293,18 +292,10 @@ function checkPropTypes(componentName, propTypes, props, location) {
292
* @param {ReactElement} element
293
*/
294
function validatePropTypes(element) {
296
- if (!(typeof element.type === 'string' ||
297
- typeof element.type === 'function')) {
298
- // This has already warned. Don't throw.
295
+ var componentClass = element.type;
296
+ if (typeof componentClass !== 'function') {
297
return;
298
}
301
- // Extract the component class from the element. Converts string types
302
- // to a composite class which may have propTypes.
303
- // TODO: Validating a string's propTypes is not decoupled from the
304
- // rendering target which is problematic.
305
- var componentClass = ReactNativeComponent.getComponentClassForElement(
306
- element
307
- );
299
var name = componentClass.displayName || componentClass.name;
300
if (componentClass.propTypes) {
301
checkPropTypes(
src/renderers/dom/client/findDOMNode.js
+1
-2
@@ -17,7 +17,6 @@ var ReactInstanceMap = require('ReactInstanceMap');
17
var ReactMount = require('ReactMount');
18
19
var invariant = require('invariant');
20
-var isNode = require('isNode');
20
var warning = require('warning');
21
22
/**
@@ -45,7 +44,7 @@ function findDOMNode(componentOrElement) {
44
if (componentOrElement == null) {
45
return null;
46
}
48
- if (isNode(componentOrElement)) {
47
+ if (componentOrElement.nodeType === 1) {
48
return componentOrElement;
49
}
50
if (ReactInstanceMap.has(componentOrElement)) {
src/renderers/dom/shared/ReactDOMComponent.js
+4
@@ -820,6 +820,10 @@ ReactDOMComponent.Mixin = {
820
this._wrapperState = null;
821
},
822
823
+ getPublicInstance: function() {
824
+ return ReactMount.getNode(this._rootNodeID);
825
+ },
826
+
827
};
828
829
ReactPerf.measureMethods(ReactDOMComponent, 'ReactDOMComponent', {
src/renderers/dom/shared/ReactDefaultInjection.js
-92
@@ -19,18 +19,15 @@ var EnterLeaveEventPlugin = require('EnterLeaveEventPlugin');
19
var ExecutionEnvironment = require('ExecutionEnvironment');
20
var HTMLDOMPropertyConfig = require('HTMLDOMPropertyConfig');
21
var ReactBrowserComponentMixin = require('ReactBrowserComponentMixin');
22
-var ReactClass = require('ReactClass');
22
var ReactComponentBrowserEnvironment =
23
require('ReactComponentBrowserEnvironment');
24
var ReactDefaultBatchingStrategy = require('ReactDefaultBatchingStrategy');
25
var ReactDOMComponent = require('ReactDOMComponent');
26
var ReactDOMIDOperations = require('ReactDOMIDOperations');
27
var ReactDOMTextComponent = require('ReactDOMTextComponent');
29
-var ReactElement = require('ReactElement');
28
var ReactEventListener = require('ReactEventListener');
29
var ReactInjection = require('ReactInjection');
30
var ReactInstanceHandles = require('ReactInstanceHandles');
33
-var ReactInstanceMap = require('ReactInstanceMap');
31
var ReactMount = require('ReactMount');
32
var ReactReconcileTransaction = require('ReactReconcileTransaction');
33
var SelectEventPlugin = require('SelectEventPlugin');
@@ -38,91 +35,6 @@ var ServerReactRootIndex = require('ServerReactRootIndex');
35
var SimpleEventPlugin = require('SimpleEventPlugin');
36
var SVGDOMPropertyConfig = require('SVGDOMPropertyConfig');
37
41
-var warning = require('warning');
42
-
43
-var canDefineProperty = false;
44
-try {
45
- Object.defineProperty({}, 'test', {get: function() {}});
46
- canDefineProperty = true;
47
-} catch (e) {
48
-}
49
-
50
-var deprecatedDOMMethods = [
51
- 'isMounted', 'replaceProps', 'replaceState', 'setProps', 'setState',
52
- 'forceUpdate',
53
-];
54
-
55
-function getDeclarationErrorAddendum(domWrapperClass) {
56
- var internalInstance = ReactInstanceMap.get(domWrapperClass);
57
- var owner = internalInstance._currentElement._owner || null;
58
- if (owner) {
59
- var name = owner.getName();
60
- if (name) {
61
- return ' This DOM component was rendered by `' + name + '`.';
62
- }
63
- }
64
- return '';
65
-}
66
-
67
-function autoGenerateWrapperClass(type) {
68
- var wrapperClass = ReactClass.createClass({
69
- tagName: type.toUpperCase(),
70
- render: function() {
71
- // Copy owner down for debugging info
72
- var internalInstance = ReactInstanceMap.get(this);
73
- return new ReactElement(
74
- type,
75
- null, // key
76
- null, // ref
77
- internalInstance._currentElement._owner, // owner
78
- this._internalProps || this.props
79
- );
80
- },
81
- });
82
-
83
- if (__DEV__) {
84
- if (canDefineProperty) {
85
- Object.defineProperty(wrapperClass.prototype, 'props', {
86
- enumerable: true,
87
- set: function(props) {
88
- this._internalProps = props;
89
- },
90
- get: function() {
91
- warning(
92
- false,
93
- 'ReactDOMComponent.props: Do not access .props of a DOM ' +
94
- 'component directly; instead, recreate the props as `render` ' +
95
- 'did originally or use React.findDOMNode and read the DOM ' +
96
- 'properties/attributes directly.%s',
97
- getDeclarationErrorAddendum(this)
98
- );
99
- return this._internalProps;
100
- },
101
- });
102
-
103
- deprecatedDOMMethods.forEach(function(method) {
104
- var old = wrapperClass.prototype[method];
105
- Object.defineProperty(wrapperClass.prototype, method, {
106
- enumerable: true,
107
- get: function() {
108
- warning(
109
- false,
110
- 'ReactDOMComponent.%s(): Do not access .%s() of a DOM ' +
111
- 'component.%s',
112
- method,
113
- method,
114
- getDeclarationErrorAddendum(this)
115
- );
116
- return old;
117
- },
118
- });
119
- });
120
- }
121
- }
122
-
123
- return wrapperClass;
124
-}
125
-
38
var alreadyInjected = false;
39
40
function inject() {
@@ -165,10 +77,6 @@ function inject() {
77
ReactDOMTextComponent
78
);
79
168
- ReactInjection.NativeComponent.injectAutoWrapper(
169
- autoGenerateWrapperClass
170
- );
171
-
80
ReactInjection.Class.injectMixin(ReactBrowserComponentMixin);
81
82
ReactInjection.DOMProperty.injectDOMPropertyConfig(HTMLDOMPropertyConfig);
src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js
+3
-3
@@ -805,12 +805,12 @@ describe('ReactDOMComponent', function() {
805
it('warns on invalid nesting at root', () => {
806
spyOn(console, 'error');
807
var p = document.createElement('p');
808
- React.render(<tr />, p);
808
+ React.render(<span><p /></span>, p);
809
810
expect(console.error.calls.length).toBe(1);
811
expect(console.error.calls[0].args[0]).toBe(
812
- 'Warning: validateDOMNesting(...): <tr> cannot appear as a child of ' +
813
- '<p>. See p > tr.'
812
+ 'Warning: validateDOMNesting(...): <p> cannot appear as a descendant ' +
813
+ 'of <p>. See p > ... > p.'
814
);
815
});
816
src/renderers/shared/reconciler/ReactCompositeComponent.js
+7
-20
@@ -15,7 +15,6 @@ var ReactComponentEnvironment = require('ReactComponentEnvironment');
15
var ReactCurrentOwner = require('ReactCurrentOwner');
16
var ReactElement = require('ReactElement');
17
var ReactInstanceMap = require('ReactInstanceMap');
18
-var ReactNativeComponent = require('ReactNativeComponent');
18
var ReactPerf = require('ReactPerf');
19
var ReactPropTypeLocations = require('ReactPropTypeLocations');
20
var ReactPropTypeLocationNames = require('ReactPropTypeLocationNames');
@@ -123,9 +122,7 @@ var ReactCompositeComponentMixin = {
122
var publicProps = this._processProps(this._currentElement.props);
123
var publicContext = this._processContext(context);
124
126
- var Component = ReactNativeComponent.getComponentClassForElement(
127
- this._currentElement
128
- );
125
+ var Component = this._currentElement.type;
126
127
// Initialize the public class
128
var inst = new Component(publicProps, publicContext);
@@ -235,8 +232,7 @@ var ReactCompositeComponentMixin = {
232
var renderedElement = this._renderValidatedComponent();
233
234
this._renderedComponent = this._instantiateReactComponent(
238
- renderedElement,
239
- this._currentElement.type // The wrapping type
235
+ renderedElement
236
);
237
238
var markup = ReactReconciler.mountComponent(
@@ -304,9 +300,7 @@ var ReactCompositeComponentMixin = {
300
*/
301
_maskContext: function(context) {
302
var maskedContext = null;
307
- var Component = ReactNativeComponent.getComponentClassForElement(
308
- this._currentElement
309
- );
303
+ var Component = this._currentElement.type;
304
var contextTypes = Component.contextTypes;
305
if (!contextTypes) {
306
return emptyObject;
@@ -329,9 +323,7 @@ var ReactCompositeComponentMixin = {
323
_processContext: function(context) {
324
var maskedContext = this._maskContext(context);
325
if (__DEV__) {
332
- var Component = ReactNativeComponent.getComponentClassForElement(
333
- this._currentElement
334
- );
326
+ var Component = this._currentElement.type;
327
if (Component.contextTypes) {
328
this._checkPropTypes(
329
Component.contextTypes,
@@ -349,9 +341,7 @@ var ReactCompositeComponentMixin = {
341
* @private
342
*/
343
_processChildContext: function(currentContext) {
352
- var Component = ReactNativeComponent.getComponentClassForElement(
353
- this._currentElement
354
- );
344
+ var Component = this._currentElement.type;
345
var inst = this._instance;
346
var childContext = inst.getChildContext && inst.getChildContext();
347
if (childContext) {
@@ -392,9 +382,7 @@ var ReactCompositeComponentMixin = {
382
*/
383
_processProps: function(newProps) {
384
if (__DEV__) {
395
- var Component = ReactNativeComponent.getComponentClassForElement(
396
- this._currentElement
397
- );
385
+ var Component = this._currentElement.type;
386
if (Component.propTypes) {
387
this._checkPropTypes(
388
Component.propTypes,
@@ -695,8 +683,7 @@ var ReactCompositeComponentMixin = {
683
ReactReconciler.unmountComponent(prevComponentInstance);
684
685
this._renderedComponent = this._instantiateReactComponent(
698
- nextRenderedElement,
699
- this._currentElement.type
686
+ nextRenderedElement
687
);
688
var nextMarkup = ReactReconciler.mountComponent(
689
this._renderedComponent,
src/renderers/shared/reconciler/ReactNativeComponent.js
-5
@@ -36,11 +36,6 @@ var ReactNativeComponentInjection = {
36
injectComponentClasses: function(componentClasses) {
37
assign(tagToComponentClass, componentClasses);
38
},
39
- // Temporary hack since we expect DOM refs to behave like composites,
40
- // for this release.
41
- injectAutoWrapper: function(wrapperFactory) {
42
- autoGenerateWrapperClass = wrapperFactory;
43
- },
39
};
40
41
/**
src/renderers/shared/reconciler/__tests__/ReactInstanceHandles-test.js
+5
-6
@@ -12,7 +12,6 @@
12
'use strict';
13
14
var React = require('React');
15
-var ReactInstanceMap = require('ReactInstanceMap');
15
var ReactTestUtils = require('ReactTestUtils');
16
var ReactMount = require('ReactMount');
17
@@ -63,11 +62,11 @@ describe('ReactInstanceHandles', function() {
62
});
63
}
64
66
- function getNodeID(instance) {
67
- if (instance === null) {
65
+ function getNodeID(el) {
66
+ if (el === null) {
67
return '';
68
}
70
- return ReactInstanceMap.get(instance)._rootNodeID;
69
+ return el.getAttribute('data-reactid');
70
}
71
72
beforeEach(function() {
@@ -389,8 +388,8 @@ describe('ReactInstanceHandles', function() {
388
// Common ancestor with grandparent is the grandparent.
389
{
390
one: parent.refs.P_P1_C1.refs.DIV_1,
392
- two: parent.refs.P_P1_C1,
393
- com: parent.refs.P_P1_C1,
391
+ two: parent.refs.P_P1,
392
+ com: parent.refs.P_P1,
393
},
394
// Grantparent across subcomponent boundaries.
395
{
src/renderers/shared/reconciler/__tests__/ReactMultiChildReconcile-test.js
-1
@@ -89,7 +89,6 @@ var FriendsStatusDisplay = React.createClass({
89
var statusDisplays =
90
ReactInstanceMap.get(this)
91
._renderedComponent
92
- ._renderedComponent
92
._renderedChildren;
93
for (name in statusDisplays) {
94
var child = statusDisplays[name];
src/renderers/shared/reconciler/instantiateReactComponent.js
+2
-7
@@ -60,11 +60,10 @@ function isInternalComponentType(type) {
60
* Given a ReactNode, create an instance that will actually be mounted.
61
*
62
* @param {ReactNode} node
63
- * @param {*} parentCompositeType The composite type that resolved this.
63
* @return {object} A new instance of the element's constructor.
64
* @protected
65
*/
67
-function instantiateReactComponent(node, parentCompositeType) {
66
+function instantiateReactComponent(node) {
67
var instance;
68
69
if (node === null || node === false) {
@@ -83,12 +82,8 @@ function instantiateReactComponent(node, parentCompositeType) {
82
);
83
84
// Special case string values
86
- if (parentCompositeType === element.type &&
87
- typeof element.type === 'string') {
88
- // Avoid recursion if the wrapper renders itself.
85
+ if (typeof element.type === 'string') {
86
instance = ReactNativeComponent.createInternalComponent(element);
90
- // All native components are currently wrapped in a composite so we're
91
- // safe to assume that this is what we should instantiate.
87
} else if (isInternalComponentType(element.type)) {
88
// This is temporarily available for custom components that are not string
89
// represenations. I.e. ART. Once those are updated to use the string
src/test/ReactTestUtils.js
+8
-5
@@ -45,7 +45,7 @@ function findAllInRenderedTreeInternal(inst, test) {
45
var publicInst = inst.getPublicInstance()
46
var ret = test(publicInst) ? [publicInst] : [];
47
if (ReactTestUtils.isDOMComponent(publicInst)) {
48
- var renderedChildren = inst._renderedComponent._renderedChildren;
48
+ var renderedChildren = inst._renderedChildren;
49
var key;
50
for (key in renderedChildren) {
51
if (!renderedChildren.hasOwnProperty(key)) {
@@ -96,7 +96,7 @@ var ReactTestUtils = {
96
isDOMComponent: function(inst) {
97
// TODO: Fix this heuristic. It's just here because composites can currently
98
// pretend to be DOM components.
99
- return !!(inst && inst.tagName && inst.getDOMNode);
99
+ return !!(inst && inst.nodeType === 1 && inst.tagName);
100
},
101
102
isDOMComponentElement: function(inst) {
@@ -116,13 +116,15 @@ var ReactTestUtils = {
116
},
117
118
isCompositeComponentWithType: function(inst, type) {
119
+ if (!ReactTestUtils.isCompositeComponent(inst)) {
120
+ return false;
121
+ }
122
var internalInstance = ReactInstanceMap.get(inst);
123
var constructor = internalInstance
124
._currentElement
125
.type;
126
124
- return !!(ReactTestUtils.isCompositeComponent(inst) &&
125
- (constructor === type));
127
+ return (constructor === type);
128
},
129
130
isCompositeComponentElement: function(inst) {
@@ -256,7 +258,8 @@ var ReactTestUtils = {
258
);
259
if (all.length !== 1) {
260
throw new Error(
259
- 'Did not find exactly one match for componentType:' + componentType
261
+ 'Did not find exactly one match for componentType:' + componentType +
262
+ ' (found ' + all.length + ')'
263
);
264
}
265
return all[0];
src/test/reactComponentExpect.js
+3
-3
@@ -85,7 +85,7 @@ assign(reactComponentExpectInternal.prototype, {
85
// change soon.
86
this.toBeDOMComponent();
87
var renderedChildren =
88
- this._instance._renderedComponent._renderedChildren || {};
88
+ this._instance._renderedChildren || {};
89
for (var name in renderedChildren) {
90
if (!renderedChildren.hasOwnProperty(name)) {
91
continue;
@@ -101,7 +101,7 @@ assign(reactComponentExpectInternal.prototype, {
101
102
toBeDOMComponentWithChildCount: function(count) {
103
this.toBeDOMComponent();
104
- var renderedChildren = this._instance._renderedComponent._renderedChildren;
104
+ var renderedChildren = this._instance._renderedChildren;
105
expect(renderedChildren).toBeTruthy();
106
expect(Object.keys(renderedChildren).length).toBe(count);
107
return this;
@@ -109,7 +109,7 @@ assign(reactComponentExpectInternal.prototype, {
109
110
toBeDOMComponentWithNoChildren: function() {
111
this.toBeDOMComponent();
112
- expect(this._instance._renderedComponent._renderedChildren).toBeFalsy();
112
+ expect(this._instance._renderedChildren).toBeFalsy();
113
return this;
114
},
115