Skip to content
This repository has been archived by the owner on Mar 23, 2023. It is now read-only.

Extending FluxContainer instantiation error with Node v6.x and ES6 #351

Open
nathankellenicki opened this issue May 10, 2016 · 20 comments
Open
Labels

Comments

@nathankellenicki
Copy link

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 nathankellenicki changed the title Extending FluxContainer instantiation error with Node v6.x Extending FluxContainer instantiation error with Node v6.x and ES6 May 10, 2016
@kyldvs
Copy link
Contributor

kyldvs commented May 10, 2016

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?

@nathankellenicki
Copy link
Author

nathankellenicki commented May 10, 2016

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.

@kyldvs
Copy link
Contributor

kyldvs commented May 10, 2016

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

@nathankellenicki
Copy link
Author

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) 

@kyldvs kyldvs added bug and removed question labels May 13, 2016
@lazy8
Copy link

lazy8 commented Aug 29, 2016

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

@murilobr
Copy link

murilobr commented Jan 2, 2017

Such a mess

@murilobr
Copy link

murilobr commented Jan 2, 2017

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

@kyldvs
Copy link
Contributor

kyldvs commented Jan 2, 2017

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

@gitsupersmecher
Copy link

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
Copy link

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

patelnav pushed a commit to patelnav/flux-container-create that referenced this issue Jul 5, 2017
patelnav pushed a commit to patelnav/flux-container-create that referenced this issue Jul 5, 2017
patelnav pushed a commit to patelnav/flux-container-create that referenced this issue Jul 5, 2017
@roshin8
Copy link

roshin8 commented May 28, 2020

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
Copy link

roshin8 commented May 28, 2020

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

Do you know what the workaround was?

@murilobr
Copy link

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

@jklimke
Copy link

jklimke commented Jun 29, 2020

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

@mertkahyaoglu
Copy link

Any updates on this?

@yangshun
Copy link
Contributor

Can you try upgrading to flux@^4.0.0?

@mertkahyaoglu
Copy link

Yes, still getting the same error.

@Horki
Copy link

Horki commented May 3, 2021

@kyldvs is this still active?

@mkermani144
Copy link

mkermani144 commented Feb 21, 2022

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.

@jklimke
Copy link

jklimke commented Apr 11, 2022

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

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests