Support arrow functions as stateless components
Paul O’Shannessy committed
Sep 12, 2015 at 18:22 UTC
e5c3fb14fa3427b331b66785d94aef404ce66156
2 files changed
+35
-10
src/renderers/shared/reconciler/ReactCompositeComponent.js
+20
-10
@@ -42,7 +42,7 @@ function StatelessComponent(Component) {
42
}
43
StatelessComponent.prototype.render = function() {
44
var Component = ReactInstanceMap.get(this)._currentElement.type;
45
- return new Component(this.props, this.context, this.updater);
45
+ return Component(this.props, this.context, this.updater);
46
};
47
48
/**
@@ -136,18 +136,26 @@ var ReactCompositeComponentMixin = {
136
var inst;
137
var renderedElement;
138
139
- if (__DEV__) {
140
- ReactCurrentOwner.current = this;
141
- try {
139
+ // This is a way to detect if Component is a stateless arrow function
140
+ // component, which is not newable. It might not be 100% reliable but is
141
+ // something we can do until we start detecting that Component extends
142
+ // React.Component. We already assume that typeof Component === 'function'.
143
+ var canInstantiate = 'prototype' in Component;
144
+
145
+ if (canInstantiate) {
146
+ if (__DEV__) {
147
+ ReactCurrentOwner.current = this;
148
+ try {
149
+ inst = new Component(publicProps, publicContext, ReactUpdateQueue);
150
+ } finally {
151
+ ReactCurrentOwner.current = null;
152
+ }
153
+ } else {
154
inst = new Component(publicProps, publicContext, ReactUpdateQueue);
143
- } finally {
144
- ReactCurrentOwner.current = null;
155
}
146
- } else {
147
- inst = new Component(publicProps, publicContext, ReactUpdateQueue);
156
}
157
150
- if (inst === null || inst === false || ReactElement.isValidElement(inst)) {
158
+ if (!canInstantiate || inst === null || inst === false || ReactElement.isValidElement(inst)) {
159
renderedElement = inst;
160
inst = new StatelessComponent(Component);
161
}
@@ -168,7 +176,9 @@ var ReactCompositeComponentMixin = {
176
// We support ES6 inheriting from React.Component, the module pattern,
177
// and stateless components, but not ES6 classes that don't extend
178
warning(
171
- Component.isReactClass || !(inst instanceof Component),
179
+ Component.isReactClass ||
180
+ !canInstantiate ||
181
+ !(inst instanceof Component),
182
'%s(...): React component classes must extend React.Component.',
183
Component.displayName || Component.name || 'Component'
184
);
src/renderers/shared/reconciler/__tests__/ReactStatelessComponent-test.js
+15
@@ -183,4 +183,19 @@ describe('ReactStatelessComponent', function() {
183
ReactDOM.render(<Parent />, el);
184
expect(el.textContent).toBe('en');
185
});
186
+
187
+ it('should work with arrow functions', function() {
188
+ // TODO: actually use arrow functions, probably need node v4 and maybe
189
+ // a separate file that we blacklist from the arrow function transform.
190
+ // We can't actually test this without native arrow functions since the
191
+ // issues (non-newable) don't apply to any other functions.
192
+ var Child = function() {
193
+ return <div />;
194
+ };
195
+ // Will create a new bound function without a prototype, much like a native
196
+ // arrow function.
197
+ Child = Child.bind(this);
198
+
199
+ expect(() => ReactTestUtils.renderIntoDocument(<Child />)).not.toThrow();
200
+ });
201
});