elsassph / haxe-redux

Haxe Redux externs and support classes for a smarter API
8 stars 2 forks source link

Support for @:connect on ReactComponent #14

Closed kLabz closed 4 years ago

kLabz commented 6 years ago

@:connect meta on ReactComponent

Add support for @:connect meta on react components, as the @connect decorator of react-redux. Note that typing is not checked here; however react-redux does some checks at runtime.

@:connect without params

If you do not provide params to the connect meta, a macro will loop through your fields to find static fields named mapStateToProps, mapDispatchToProps, mergeProps or options and use those it found.

@:connect
class MyComponent extends ReactComponentOfProps<Props>
{
    static function mapDispatchToProps(dispatch:Dispatch):Props
    {
        return {
            onClick: function() return dispatch(Actions.Click)
        };
    }

    override public function render()
    {
        return jsx('
            <button onClick=${props.onClick} />
        ');
    }
}

Providing params

You can use any function instead of your own static fields.

@:connect(null, Helpers.myMapDispatchToProps)
class MyComponent extends ReactComponentOfProps<Props> {}

Or even declare your function inline, if you're into this:

@:connect(null, function(dispatch:Dispatch) return {onClick: function() return dispatch(Actions.Click))
class MyComponent extends ReactComponentOfProps<Props> {}

Please note that you must respect the order of arguments of ReactRedux.connect(), so you must pass null as first argument if you only want to define mapDispatchToProps, for example.

kLabz commented 6 years ago

Note: this is roughly the same as doing:

import redux.react.ReactRedux.connect;

@:jsxStatic('connected')
class MyComponent extends ReactComponentOfProps<Props>
{
    public static var connected = connect(null, mapDispatchToProps)(MyComponent);

    static function mapDispatchToProps(dispatch:Dispatch):Props
    {
        return {
            onClick: function() return dispatch(Actions.Click)
        };
    }

    override public function render()
    {
        return jsx('
            <button onClick=${props.onClick} />
        ');
    }
}

Which in itself can continue to be a useful trick when working with multiple HOCs.

kLabz commented 6 years ago

TODO: fix an issue with compiler server

Edit: fixed

kLabz commented 6 years ago

I extracted the ReactRedux extern in #15, if you have doubts about @:connect at least the extern could be merged.

elsassph commented 6 years ago

Please fix the conflict, I think it's worth merging - then we should consider deprecating the previous method.

kLabz commented 6 years ago

I'm actually working on something that would imply some modifications here :D

I am thinking about a @:wrap (or @:hoc) meta in haxe-react for ReactComponent, which would wrap the component inside one (or many) hoc like ReactRouter.withRouter, ReactIntl.injectIntl, and ReactRedux.connect(...) which is used here.

@:connect would not change much, but would generate a @:wrap(ReactRedux.connect(mapStateToProps, ...)) and let the @:wrap macro handle the creation of the @:jsxStatic meta and function.

kLabz commented 6 years ago

The feature can be tested with my test project https://github.com/kLabz/haxe-redux-todo/tree/feature/react-wrap-redux-connect. I added a small demo in view.comp.filterLink.FilterLink.

Use these temp haxelibs to make it work as if @:wrap was added to haxe-react and @:connect to haxe-redux:

haxelib git react-wrap git@github.com:kLabz/haxe-react-wrap.git
haxelib git redux-connect git@github.com:kLabz/haxe-redux-connect.git feature/react-wrap

I'll create the PR in haxe-react, too. It will include the sources and extraParams from https://github.com/kLabz/haxe-react-wrap.

This feature won't work until @:wrap is merged and released in haxe-react, though. I don't know what you are planning regarding releases of haxe-react and haxe-redux, but they should be synchronized for this to work (so maybe this PR should be merged later?).