flux
flux copied to clipboard
Extending FluxContainer instantiation error with Node v6.x and ES6
Hi,
When attempting to extend FluxContainer and create a class from it on the server side in Node v6.x, the component throws an error when instantiated:
TypeError: Class constructor OverviewComponent cannot be invoked without 'new'
at PureFluxContainerClass.FluxContainerClass (/ProjectLocation/node_modules/flux/lib/FluxContainer.js:50:13)
The component looks like this:
class OverviewComponent extends React.Component {
...
}
module.exports = Flux.Container.create(OverviewComponent);
Note that this is not transpiled - this is executed natively with Node v6.x's ES6 support.
I believe this error is because Flux is expecting the component to be transpiled to ES5, and therefore be able to call the constructor be calling it directly, which it can't do in ES6. Is this correct?
I'm not sure if we will try to support this or suggest to just use transpiled files, but please provide more information to debug. What precisely is the line of code that is throwing?
Why would you suggest using transpiled files? ES6 should eventually be natively supported in runtimes, so Flux should follow the ES6 spec properly. It so happens that Node v6.x is there now.
I believe all the information necessary is displayed above. In FluxContainer.js on line 50 (Of the built version), it calls:
_Base.call(this, props);
Inside the create() function. _Base in this instance is the passed component - OverviewComponent in my case, so essentially the code is calling OverviewComponent.call(this, props), or effectively OverviewComponent(props).
In ES6 one cannot call the constructor directly, you must use "new" to instantiate the class.
Okay I was misunderstanding, you mean your code is not transpiled, the lib/FluxContainer
code is transpiled.
This may just mean we need to turn on stricter options when building, can you try
1: Change this line to false: https://github.com/facebook/flux/blob/master/scripts/babel/default-options.js#L24
2: Run npm run prepublish
3: And then try to run your code again
Thanks for the response Kyle. I've just tried that and unfortunately I had the same results.
- Fresh clone into my local node_modules
- Change scripts/babel/default-options.js#L24
- npm install
TypeError: Class constructor OverviewComponent cannot be invoked without 'new'
at PureFluxContainerClass.FluxContainerClass (/ProjectDir/node_modules/flux/lib/FluxContainer.js:54:86)
at new PureFluxContainerClass (/ProjectDir/node_modules/flux/lib/FluxContainer.js:177:90)
at ReactCompositeComponentMixin._constructComponentWithoutOwner (/ProjectDir/node_modules/react/lib/ReactCompositeComponent.js:248:14)
at ReactCompositeComponentMixin._constructComponent (/ProjectDir/node_modules/react/lib/ReactCompositeComponent.js:236:21)
at ReactCompositeComponentMixin.mountComponent (/ProjectDir/node_modules/react/lib/ReactCompositeComponent.js:159:21)
at wrapper [as mountComponent] (/ProjectDir/node_modules/react/lib/ReactPerf.js:66:21)
at Object.ReactReconciler.mountComponent (/ProjectDir/node_modules/react/lib/ReactReconciler.js:39:35)
at ReactDOMComponent.ReactMultiChild.Mixin.mountChildren (/ProjectDir/node_modules/react/lib/ReactMultiChild.js:203:44)
at ReactDOMComponent.Mixin._createContentMarkup (/ProjectDir/node_modules/react/lib/ReactDOMComponent.js:593:32)
at ReactDOMComponent.Mixin.mountComponent (/ProjectDir/node_modules/react/lib/ReactDOMComponent.js:478:29)
If anyone else comes across this, here is a possible (ugly) workaround:
/// FluxContainerConverter.js
module.exports = {
convert: function(containerClass) {
const tmp = containerClass;
containerClass = function(...args) {
return new tmp(...args);
};
containerClass.prototype = tmp.prototype;
containerClass.getStores = tmp.getStores;
containerClass.calculateState = tmp.calculateState;
return containerClass;
}
};
Now you can use it to create your FluxContainer like this:
var fluxContainerConverter = require('./FluxContainerConverter');
Container.create(
fluxContainerConverter.convert(MyComponent));
Such a mess
There is a sample in official docs page, but doesn't work! It's brilliant. http://facebook.github.io/flux/docs/flux-utils.html#container
@murilobr, the example does work on the client (most use cases), and there is a workaround on the server as mentioned above. I'm not sure why it's broken on the server, but PRs are welcome.
Sad but true! Flux Containers is not working with es6. I do not understand why is not fixed till now, in this long period of time.
@murilobr - thanks providing the workaround. It really helps.
There is a sample in official docs page, but doesn't work! It's brilliant. http://facebook.github.io/flux/docs/flux-utils.html#container
Could you tell what that example was?
@murilobr - thanks providing the workaround. It really helps.
Do you know what the workaround was?
@murilobr - thanks providing the workaround. It really helps.
Do you know what the workaround was?
Don’t remember. Sorry. The page doesn’t exists anymore. :(
That is still a problem as there is no newer version available at npm ?
Any updates on this?
Can you try upgrading to flux@^4.0.0?
Yes, still getting the same error.
@kyldvs is this still active?
Same issue happens if someone tries to use vite
, as vite
treats source code (in our case, the component which is passed to Container.create
) as native ESM and doesn't bundle it to ES5.
Anyway, @lazy8's answer works for now. I have changed it a bit so I don't have to call the converter everywhere:
// bootstrap.js
import { Container } from 'flux/utils';
const containerCreateOld = Container.create;
// Change `Container.create` implementation based on @lazy8's answer
Container.create = (Component, options) => {
const newComponent = (...args) => new Component(...args);
newComponent.prototype = Component.prototype;
newComponent.getStores = Component.getStores;
newComponent.calculateState = Component.calculateState;
return containerCreateOld(newComponent, options);
};
then import the above bootstrap file before any import { Container } from 'flux/utils';
statements.
I had an issue with the previous solution. It did not respect defaultProps of my component class. I changed it to apply the default props the new component and it seems to work.
// bootstrap.js
import { Container } from 'flux/utils';
const containerCreateOld = Container.create;
// Change `Container.create` implementation based on @lazy8's answer
Container.create = (Component, options) => {
const newComponent = (...args) => new Component(...args);
newComponent.prototype = Component.prototype;
newComponent.defaultProps = Component.defaultProps;
newComponent.getStores = Component.getStores;
newComponent.calculateState = Component.calculateState;
return containerCreateOld(newComponent, options);
};