Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use haxe-react when react installed as a package #8

Closed
zabojad opened this issue Oct 26, 2015 · 13 comments
Closed

Use haxe-react when react installed as a package #8

zabojad opened this issue Oct 26, 2015 · 13 comments

Comments

@zabojad
Copy link

zabojad commented Oct 26, 2015

I'm struggling with using React addons components with haxe-react.

The problem is that most react addons are distributed as npm packages. They usually contains var React = require('react') statements which makes browserify including react in the output file (I did not find a way to exclude it from the output file).

On the other side, haxe-react seems to work only when React is used not as an npm package, but rather included via a script tag in the html page header.

The problem with this is that there can be only one React included at a time. If not, we get the following error at runtime:

Uncaught Error: Invariant Violation: addComponentAsRefTo(...): Only a ReactOwner can have refs. You might be adding a ref to a component that was not created inside a component's `render` method, or you have multiple copies of React loaded (details: https://fb.me/react-refs-must-have-owner).

If then I remove the script tags that import react and react-dom, I get of course this, as my compile haxe-react code does not find React:

Uncaught ReferenceError: React is not defined

As it seems that react components are distributed as npm packages only, the way would be to make haxe-react work with an npm version of React. How can we do that ?

@zabojad
Copy link
Author

zabojad commented Oct 26, 2015

I've added manually this:

var React = require('react');
var ReactDOM = require('react-dom');

(function (console) { "use strict";
// ...

to my haxe js output before it gets browserifyied and it works...

What would be the clean way to do this in haxe-react ?

@elsassph
Copy link
Contributor

Yes currently haxe-react depends on including React as a JS, not through require - we're looking into this but didn't use addons yet.

Making the current externs require friendly you have just to add the @:jsRequire meta like that:

@:jsRequire('react')
@:native('React')
extern class React {...
@:jsRequire('react', 'Component')
@:native('React.Component')
extern class ReactComponentOf {...
@:jsRequire('react-dom')
@:native('ReactDOM')
extern class ReactDOM {...

Of course you then have to use Browserify or Webpack to get it to work.

I'm working on an example which will introduce this change, but you can quickly do the change yourself for now - if you manage to use some addons that would be helpful to share it.

@zabojad
Copy link
Author

zabojad commented Oct 26, 2015

Thanks for your answer.

I will definitively share my work on using haxe-react with react addons and libs (material-ui for example). It will be a set of haxe externs basically...

@elsassph
Copy link
Contributor

@zabojad did you try to use the ReactWithAddOns bundle? https://facebook.github.io/react/blog/2015/10/28/react-v0.14.1.html
When the JS is loaded I can see that React.addons.CSSTransitionGroup is global.

We definitiely need at some point to support require but for now you could make externs without changing the base library.

@zabojad
Copy link
Author

zabojad commented Oct 29, 2015

@elsassph yes, I've tried it from there https://facebook.github.io/react/downloads.html

But what I do now is that I define externs with the @:jsRequire meta tag. I'm not only using the "official" react addons but also other react components like the material-ui ones. Externs + @:jsRequire + browserify works perfectly.

I'll come back to you later with a complete set of externs for what I've used to get your two cents on one or two things...

@elsassph
Copy link
Contributor

Just pushed the @:jsRequire annotations on master.

@zabojad
Copy link
Author

zabojad commented Jan 14, 2016

Hi @elsassph !
I had to pause my work with haxe-react for few weeks but now I'm back to it.
Regarding third party react components externs, I'm not sure about how to write them to enforce compile time checking on components props and fields...
Here is an example:

@:jsRequire("material-ui/lib/toggle")
extern class Toggle {

}

Toggle is a genuine react component. However, how could you write its extern so that when I use it with the jsx() macro, it would check the props I would use on it?

I would need something like:

import api.react.ReactComponent;

typedef ToggleProps = {
    defaultToggled : Bool,
    elementStyle : Dynamic,
    label : Dynamic,
    labelStyle : Dynamic,
    labelPosition : String,
    name : String,
    style : Dynamic,
    value : String
}

extern class Toggle extends ReactComponentOf<ToggleProps, Dynamic, Dynamic> { }

But of course that won't work... What would be the right way to define those externs?

@dpeek
Copy link
Contributor

dpeek commented Jan 14, 2016

I wonder if this would work?
extern typedef Toggle = ReactComponentOf<ToggleProps, Dynamic, Dynamic>

@zabojad
Copy link
Author

zabojad commented Jan 14, 2016

@dpeek it compiles, but doesn't do any type checking at compile time...

@dpeek
Copy link
Contributor

dpeek commented Jan 14, 2016

Ah, I see what you mean. It will compile time check if you subclass it at least. Infact I was just talking to @elsassph about compile time checking of props in JSX – I think it's possible...

@zabojad
Copy link
Author

zabojad commented Jan 14, 2016

@dpeek mmm, that sound like a good idea. In that case, it would go through the jsx macro context and indeed be type checked at compilation... It creates quite some extra work at creating "externs" though...

It might be "ignorable" but I've crossed one case where I couldn't subclass a comp because it is designed "final". The Tab cmp from material-ui for example cannot be subclassed because its natural parent component (Tabs) will detect it at runtime and won't allow it...

@zabojad
Copy link
Author

zabojad commented Jan 19, 2016

Hi there !
Do you have any idea other than extending (wrapping actually) an extern component to enforce compiler type checking on its properties ?
Thanks !

@elsassph
Copy link
Contributor

The initial issue question was covered so I'm closing the issue.

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

No branches or pull requests

3 participants