0

I'm trying to figure out how to use react-rails with my Rails 5 gem.

At the moment, I'm trying to follow the tutorial in this post. https://medium.com/technically-speaking/isomorphic-reactjs-app-with-ruby-on-rails-part-1-server-side-rendering-8438bbb1ea1c#.iwd44r60v

I can't get the page to render at present. I use app_roles instead of posts, but otherwise I've followed the steps shown in the tutorial.

I have two files in my app/assets/javascripts/components folder.

app_role.js.jsx has:

var AppRole = React.createClass({
    render: function() {
        return (
            <div className="h2">
                <AppRoleHeader app_role={this.props.app_role} />
                <AppRoleContent app_role={this.props.app_role} />
            </div>
        );
    }
});
var AppRoleHeader = React.createClass({
    render: function() {
        return (
            <div className="label">
                <h2>{this.props.app_role.title}</h2>
                <div className="label">
                    By {this.props.app_role.title} – {this.props.app_role.created_at}
                </div>
            </div>
        );
    }
});

var AppRoleContent = React.createClass({
    render: function() {
        return (
            <div className="label">
                {this.props.app_role.display_name}
            </div>
        );
    }
});

app_roles_list.js.jsx has:

var AppRolesList = React.createClass({
    getInitialState: function() {
        return { posts: this.props.initialAppRoles };
    },

    render: function() {
        var posts = this.state.app_roles.map(function(app_role) {
            return <AppRole key={app_role.id} app_role={app_role} />;
        });

        return (
            <div className="label">
                {app_roles}
            </div>
        );
    }
});

When I try to render this in my app_roles/index.html.erb file with:

<%= react_component('AppRolesList',
                    { initialAppRoles: @app_roles },
                    { prerender: params[:noprerender].nil? }) %>

I get an error that says:

ExecJS::RuntimeError at /app_roles
/private/var/folders/75/70zm4s4j14q74tfqpjvh49s80000gp/T/execjs20161015-7497-1bhq2x0js:24066
        return <div className="h2">
               ^

SyntaxError: Unexpected token <
    at exports.runInThisContext (vm.js:53:16)
    at Module._compile (module.js:373:25)
    at Object.Module._extensions..js (module.js:416:10)
    at Module.load (module.js:343:32)
    at Function.Module._load (module.js:300:12)
    at Function.Module.runMain (module.js:441:10)
    at startup (node.js:139:18)
    at node.js:974:3

I don't understand this error message. I've read some posts describing a problem where the return method has two elements being returned. I tried removing the div h2 tag altogether and putting the two returned elements in an array, but that didn't work either.

I have also read posts describing problems configuring babel. I don't follow the gist of those comments. In my config development.rb, I have:

config.react.variant = :development
  config.react.addons = true
  config.react.jsx_transform_options = {
    blacklist: ['spec.functionName', 'validation.react', 'strict'], # default options
    # optional: ["transformerName"],  # pass extra babel options
    whitelist: ["useStrict"] # even more options
  }

I'm not sure what I'm supposed to write in the optional: field. I assumed react-rails would give me some kind of default settings that would automatically work.

I also tried adding:

/** @jsx React.DOM */

to the top of each of the component files. Although that makes no difference to the problem.

I also tried adding this to config/application.rb

config.react.jsx_transformer_class = React::JSX::JSXTransformer

That doesn't change anything either.

I also tried adding this on my command line:

npm install --save-dev babel-preset-react

It made no difference to this problem.

Can anyone see what I need to do to get this page to load?

Application.js has:

//= require jquery
//= require jquery_ujs
//= require tether
//= require bootstrap-sprockets
//= require turbolinks
//= require react
//= require react_ujs
// require react_bootstrap
//= require components
//= require_tree .
Community
  • 1
  • 1
Mel
  • 2,481
  • 26
  • 113
  • 273
  • 1
    I don't know what kind of pre-setup project stub you are using but that error can mean only one thing: `babel` is not setup properly. – mostruash Oct 15 '16 at 00:32
  • Ok - I don't know what "pre-setup project stub" means. I am using react-rails. I followed the setup instructions for that gem. Do you know where to find babel config instructions for react-rails? I have node installed. I didn't know I had to search for separate instructions to finish configuring an app to work with rails. – Mel Oct 15 '16 at 00:36
  • It is supposed to make your life easier by setting things up correctly and putting configurations in place you had to do by yourself, but apperantly it's not so helpful. You won't find many people here that has experience with a "react-rails" gem so good luck. – mostruash Oct 15 '16 at 01:00
  • Do you know of a product that configures a rails app to work with react-rails? I don't mind starting a new app to get this working. – Mel Oct 15 '16 at 01:11
  • Can you also add `application.js` code? I followed [this](https://www.airpair.com/reactjs/posts/reactjs-a-guide-for-rails-developers) tutorial and was able to set up. – Sahil Oct 15 '16 at 06:13
  • @sahil -hi. Thanks. I added my application.js. I wonder if its because your tutorial uses coffee script? I also noticed that it doesnt recommend removing ruby racer from the gem file (which mine does). – Mel Oct 15 '16 at 06:50

1 Answers1

1

Couple of things to fix:

var AppRolesList = React.createClass({
    getInitialState: function() {
        return { posts: this.props.initialAppRoles };
    },

    render: function() {
        var posts = this.state.app_roles.map(function(app_role) {
            return <AppRole key={app_role.id} app_role={app_role} />;
        });

        return (
            <div className="label">
                {app_roles}
            </div>
        );
    }
});

You are copying the initialAppRoles prop into the posts state variable (which is mostly an anti-pattern), but then you expect this.state.app_roles which is never set.

You should just delete the whole getInitialState function here and directly use:

var posts = this.props.initialAppRoles.map(function(app_role) {
  return <AppRole key={app_role.id} app_role={app_role} />;
});

Second bug to fix: you are creating an array of posts in the render function, but then you have app_roles in your return which is not set. Correct that to have:

return (
  <div className="label">
    {posts}
  </div>
);

I copied pasted your code into my Rails setup (which uses react-rails) and it worked with prerendering on and off.

On a side note, I strongly recommend having one component per .js.jsx file with the underscore cased name of the component as its name. It'll make things easier to find in the future.

Community
  • 1
  • 1
tirdadc
  • 4,603
  • 3
  • 38
  • 45