Ad

Mixin Functions Only Work In Render()

- 1 answer

For some reason, it appears that mixin functions in my code only work properly in render() function. It could be that I'm not calling them in the right manner outside of the render(), but shouldn't it be exactly the same way?

This way everything works fine (but I can't stick with thi calling them in the right manner outside of the render(), but shouldn't it be exactly the same way?

This way everything works fine (but I can't stick with this since I have to add some extra stuff to click handling, at the same time not altering the mixin):

var Row = React.createClass({
    mixins: [someMixin]
    },

    render: function () {
        var clickHandler = null;
        var btn = null;

        if (firstCase) {
            clickHandler = this.order(this.props.name, this.props.else);
            btn = (<a target="_blank" rel="nofollow noreferrer" target="_blank" rel="nofollow noreferrer" href="" onClick={clickHandler}>Order</a>);
        } else if (secondCase) {
            clickHandler = this.noOrder(this.props.name, this.props.else);
            btn = (<a target="_blank" rel="nofollow noreferrer" target="_blank" rel="nofollow noreferrer" href="" onClick={clickHandler}>No order</a>);
        }
        return (
            <div>
                {btn}
            </div>
        );
    }
});

But when I do the obvious and include the mixin functions in another function to handle the click - like this - everything fails and even 'test' is not printed in the console:

var Row = React.createClass({
    mixins: [someMixin]
    },

    handleOrderClick(type) {
        console.log('test');
        if (type == 'order') {
            this.order(this.props.name, this.props.else);
        } else if (type == 'no-order') {
            this.noOrder(this.props.name, this.props.else);
        }
    },

    render: function () {
        var clickHandler = null;
        var btn = null;

        if (firstCase) {
            clickHandler = this.handleOrderClick('order');
            btn = (<a target="_blank" rel="nofollow noreferrer" target="_blank" rel="nofollow noreferrer" href="" onClick={clickHandler}>Order</a>);
        } else if (secondCase) {
            clickHandler = this.handleOrderClick('no-order');
            btn = (<a target="_blank" rel="nofollow noreferrer" target="_blank" rel="nofollow noreferrer" href="" onClick={clickHandler}>No order</a>);
        }
        return (
            <div>
                {btn}
            </div>
        );
    }
});

EDIT: order and noOrder functions look like this:

order: function (name, else) {
    return function (event) {
        event.preventDefault();

        var term = name + '&&¤%' + else;
        Order.order(name, else, period, function (data) {

            if (term === (global || window).MAIN_NAME + '.' + (global || window).MAIN) {
                $(window).trigger('Name:update');
            }
        }.bind(this));
    }.bind(this);
},

noOrder: function (name, else) {
    return function (event) {
        event.preventDefault();

        if (!this.state.transferModalOpen) {
            this.toggleTransferModal();
        }
    }.bind(this);
}
Ad

Answer

In order to use this.setState in handleOrderClick you'll have to use the bind method in your render method. Therefore handleOrderClick will become:

handleOrderClick(type, event) {
    this.setState({foo: 'bar'});
    if (type == 'order') {
        this.order(this.props.name, this.props.else)(event);
    } else if (type == 'no-order') {
        this.noOrder(this.props.name, this.props.else)(event);
    }
},

and your render method becomes:

render: function () {
    var clickHandler = null;
    var btn = null;

    if (firstCase) {
        clickHandler = this.handleOrderClick.bind(this, 'order');
        btn = (<a target="_blank" rel="nofollow noreferrer" target="_blank" rel="nofollow noreferrer" href="" onClick={clickHandler}>Order</a>);
    } else if (secondCase) {
        clickHandler = this.handleOrderClick(this, 'no-order');
        btn = (<a target="_blank" rel="nofollow noreferrer" target="_blank" rel="nofollow noreferrer" href="" onClick={clickHandler}>No order</a>);
    }
    return (
        <div>
            {btn}
        </div>
    );
}

You'll notice that the functions that are returned by this.order and this.noOrder are no longer returned by handleOrderClick, but are instead executed immediately. This should provide the effect you desire.

I've put the code in your example into a jsfiddle and it now seems to be working correctly. I've had to change the prop 'else' to 'alt' because 'else' is a reserved word. I've also just applied the mixin to the class directly for simplicity. I have simpilfied the order and noOrder functions as I don't have access to the Order object and we are only interested in them firing at the correct time. I've also added a second button that you can click to flip the cases so the other button is rendered, causing the component to render again. I've added a label that will display which function had been called when the button was last pressed.

for reference, you can find more information about the bind method here.

Hope this helps ^_^

Ad
source: stackoverflow.com
Ad