Heikki Mustonen
Heikki Mustonen

Reputation: 311

Using serverside HTML-templates with ReactJS

I'm struggling with Reactjs and component rendering.

Basically I've regular html-templates at the server and I'm trying to use them as a JSX-components with the React. Otherwise it works just fine, but I'm not able to fire the events for example: this.handleSubmit.

How to render the loaded template as a React-element?

//Template /index.html
<form onSubmit={this.handleSubmit}>
    <input type="text">
    <input type="submit"
</form>

//Template loader
var App = React.createClass({
    componentDidMount: function() {
         this.updateContent();
    },
    updateContent: function(){
        /**
         * Loads the template from the server and sets 
         * a new state
         */
        var url = this.props.source.slice(1);
        $.get(url, function(result) {
            var html = result;
            if (this.isMounted()) {
                this.setState({
                    content: html
                });
            }
        }.bind(this));
    },
    handleSubmit: function(){
        console.log('Submit fired');
    }
    render: function() {
        var converter = new HTMLtoJSX({createClass: false});
        var jsx = '/** @jsx React.DOM */ ' + converter.convert(this.state.content);
        return (
            <div>
                {JSXTransformer.exec(jsx)}
            </div>
     );
});

React.render(
  <App source="#/index.html" />,
  mountPoint
);

Upvotes: 1

Views: 3939

Answers (2)

jmingov
jmingov

Reputation: 14003

The template should be precompiled using React.renderToString(), then the html returned from the function has all the extra DOM attributes such as data-react-id needed to make a reconciliation with the client.

This is because the onSubmit={this.handleSubmit} in your template doesn't have the react data associated, react doesnt care/know about it.

React can render clean html too without the bloat using React.renderToStaticMarkup() function;

Take a look here http://facebook.github.io/react/docs/top-level-api.html#react.rendertostring

Upvotes: 1

Brigand
Brigand

Reputation: 86250

JSX isn't templates for a markup language, it's a syntax extension to the JavaScript programming language. The distinction is important here.

You need to convert JSX to JS (usually done when building your project). If we modify your code to be valid JSX it looks like this:

<form onSubmit={this.handleSubmit}>
    <input type="text" />
    <input type="submit" />
</form>

And when run through the jsx tools the output is the following JavaScript expression.

React.createElement("form", {onSubmit: this.handleSubmit}, 
    React.createElement("input", {type: "text"}), 
    React.createElement("input", {type: "submit"})
)

You need to execute this code in render, with the correct this context. You could do this by wrapping the above in a function before serving it to the client:

function renderThingy(){
    React.createElement("form", {onSubmit: this.handleSubmit}, 
        React.createElement("input", {type: "text"}), 
        React.createElement("input", {type: "submit"})
    )
}

And calling that in render:

render: function() {
    return (
        <div>
            {renderThingy.call(this)}
        </div>
     );
}

This is of course confusing, and it's not apparent if handleSubmit is used by anything. Then of course, there's the issue of loading code asynchronously... I'd rather not delve into that here.

This also severely limits what you can do in your 'template', and various other problems will pop up.

tl;dr don't do this


If you want to use JSX on the server: cool, you just need a JS runtime, and a component. React.renderToString or React.renderToStaticMarkup will take care of actually giving you valid html.

Upvotes: 1

Related Questions