@samitouri / QOS-React-2 / commits / e5c3fb14fa

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 });