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

Passing a React class as a prop no longer works in 0.13.* #3652

Closed
ezequiel opened this issue Apr 12, 2015 · 8 comments
Closed

Passing a React class as a prop no longer works in 0.13.* #3652

ezequiel opened this issue Apr 12, 2015 · 8 comments

Comments

@ezequiel
Copy link

Hi,

I'm trying to run the following code using the latest version of React:

var MyComponent = React.createClass({
    render: function() {
        return (
            <div>
                <this.props.template 
                    data='test'
                />
            </div>
        );
    }
});

var App = React.createClass({
    render: function() {
        return (
            <MyComponent 
                template={this.template}
            />
        );
    },

    template: React.createClass({
        render: function() {
            return <p>{this.props.data}</p>;
        }
    })
});

React.render(<App />,  document.body);

However, an error is thrown once the code is ran: "Uncaught TypeError: Cannot read property 'mountComponent' of undefined"

The above code functions as expected in React 0.12.2. Someone figured out this is due to a change in the way React 0.13.* classes autobinds all of its methods. Therefore, changing App's render method to this fixes the issue:

    render: function() {
        var tmpl = React.createClass({
            render: function() {
                return <p>{this.props.data}</p>;
            }
        });

        return (
            <MyComponent 
                template={tmpl}
            />
        );
    }
@ezequiel ezequiel changed the title Passing a React Class as a prop no longer works in 0.13.* Passing a React class as a prop no longer works in 0.13.* Apr 12, 2015
@zpao
Copy link
Member

zpao commented Apr 13, 2015

This doesn't seem intentional. I also can't repro in master. If we can track down what fixed this, it might be worth backporting into 0.13. cc @sebmarkbage, @spicyj

@sebmarkbage
Copy link
Collaborator

This might have something to do with the binding itself. We used to effectively call new this.template.type() which is not a bound function. However, we now switched to calling new this.template() which is a bound function. However, calling native .bind() should not bind this for the Construct operation which is invoked when you call new on a function.

If that is the problem, then this should still work in the production build, if no polyfill overrides .bind().

@sebmarkbage
Copy link
Collaborator

Actually, this particular issue is probably more related to #3638 but there might be secondary issues with this pattern after that.

@syranide
Copy link
Contributor

For posterity, never ever do:

    render: function() {
        var tmpl = React.createClass({
            render: function() {
                return <p>{this.props.data}</p>;
            }
        });

        return (
            <MyComponent 
                template={tmpl}
            />
        );
    }

You're creating a new class every render which is slow and doesn't reconcile.

@sophiebits
Copy link
Contributor

To be clear, you can do this instead:

var Template = React.createClass({
    render: function() {
        return <p>{this.props.data}</p>;
    }
});

var App = React.createClass({
    render: function() {
        return <MyComponent template={Template} />;
    }
});

@zpao
Copy link
Member

zpao commented Apr 14, 2015

This is fixed by #3638

@zpao zpao closed this as completed Apr 14, 2015
@basharov
Copy link

@spicyj Your solution worked for me, but I have a question.
I do it in a similar way as your example is. Say, in place of Template I want to put a React class, like you do, or just a set of DOM elements, like <div> some content</div>.

In case I have it as a class, I run it as <Template someprops={someprops} /> inside MyComponent, but if I have it as a DOM element, then it's not a function, and should be put as it is.

The question is - should I check the type of Template variable and depending on it render it differently?

Thanks!

@sophiebits
Copy link
Contributor

If Template is 'div', then <Template /> will render a div. You can also pass <MyComponent element={<div>some content</div>} /> and return this.props.element inside MyComponent.

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

6 participants