React-Rails - problems getting started

2019-09-13 19:23发布

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 .

1条回答
爱情/是我丢掉的垃圾
2楼-- · 2019-09-13 20:25

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.

查看更多
登录 后发表回答