flux icon indicating copy to clipboard operation
flux copied to clipboard

Extending FluxContainer instantiation error with Node v6.x and ES6

Open nathankellenicki opened this issue 8 years ago • 20 comments

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?

nathankellenicki avatar May 10 '16 12:05 nathankellenicki

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?

kyldvs avatar May 10 '16 14:05 kyldvs

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.

nathankellenicki avatar May 10 '16 15:05 nathankellenicki

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

kyldvs avatar May 10 '16 20:05 kyldvs

Thanks for the response Kyle. I've just tried that and unfortunately I had the same results.

  1. Fresh clone into my local node_modules
  2. Change scripts/babel/default-options.js#L24
  3. 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) 

nathankellenicki avatar May 11 '16 10:05 nathankellenicki

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

lazy8 avatar Aug 29 '16 16:08 lazy8

Such a mess

murilobr avatar Jan 02 '17 14:01 murilobr

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 avatar Jan 02 '17 14:01 murilobr

@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.

kyldvs avatar Jan 02 '17 19:01 kyldvs

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.

gitsupersmecher avatar Apr 29 '17 20:04 gitsupersmecher

@murilobr - thanks providing the workaround. It really helps.

gitsupersmecher avatar Apr 29 '17 20:04 gitsupersmecher

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?

roshin8 avatar May 28 '20 00:05 roshin8

@murilobr - thanks providing the workaround. It really helps.

Do you know what the workaround was?

roshin8 avatar May 28 '20 00:05 roshin8

@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. :(

murilobr avatar May 28 '20 00:05 murilobr

That is still a problem as there is no newer version available at npm ?

jklimke avatar Jun 29 '20 15:06 jklimke

Any updates on this?

mertkahyaoglu avatar Jan 27 '21 10:01 mertkahyaoglu

Can you try upgrading to flux@^4.0.0?

yangshun avatar Jan 27 '21 11:01 yangshun

Yes, still getting the same error.

mertkahyaoglu avatar Jan 28 '21 08:01 mertkahyaoglu

@kyldvs is this still active?

Horki avatar May 03 '21 17:05 Horki

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.

mkermani144 avatar Feb 21 '22 10:02 mkermani144

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

jklimke avatar Apr 11 '22 15:04 jklimke