-
Notifications
You must be signed in to change notification settings - Fork 754
View helper to render react component #17
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
Conversation
I think this is an awesome idea, though I'm not totally sold on the details. Some concerns:
|
Thanks for your comments! The above implementation is just a draft. About your concerns:
<%= content_tag :div, class: "strong" do -%>
Hello world!
<% end -%> |
👍 |
Maybe 2 helpers? Maybe there's another option for turbolinks... I haven't looked at how Rails does it's built-in JSy stuff works (eg. confirm dialogs) but when I looked years ago they were all inline scripts. I'm guessing that's not the case anymore, but maybe there are some ideas we can borrow for solving this. Or just fix turbolinks :) For children, I actually meant something like this: I think we should leave server rendering out entirely for the moment, but I like where you're headed. |
I have attached some code :) Have a look and if no big problem, I am going to write some test and update README. Notes:
|
"var e=document.getElementById('#{element_id}');" \ | ||
"e&&React.renderComponent(#{name}(#{args.to_json}),e);" + | ||
events.map do |event| | ||
"document.removeEventListener('#{event}',arguments.callee)" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
arguments.callee
is deprecated so let's not use it and just use f
.
Otherwise, I think my only other comment is that I don't like the JS style. Don't let that spacebar scare you :P
Umm, travis status is still unavailable. I doubt whether it runs (I guess it probably need something like |
Sorry, I haven't had a chance to look at this again, but hopefully I'll have a chance over the weekend. I'll try to figure out the Travis issue too. Don't feel obligated to squash. I don't mind a merge commit for something like this where there are substantial changes in each commit. If it were a 10 line diff with 10 commits, then I might have an issue ;) |
It doesn't matter. I mean I am not hurry, at all. Take your time. Enjoy the weekend and don't be bothered with work stuff :) |
I found capybara-webkit is not travis-friendly and switched to poltergeist, which uses external phantomjs. After some trial and error it's working now 😃 There may be some wording issues because English is not my native language. Except that, I think it's merge-ready. |
I'd like to write my thoughts and plans here. Recently I am busy with my graduation and this situation will probably continue for another several weeks. I will finish this PR after that. The implementation and tests are complete. However, the inline script approach doesn't feel good. Something like using data attributes and initialize them dynamically like Cons:
Pros:
Comments? EDIT: Added 2 items in Pros. |
I have no opposition to evolving the pattern. So if inline script tags is how we start and we make it better later, fine by me. I'm not writing Rails much anymore so I'm not a good person to decide. But personally, I'd rather have 1 less dependency to have to figure out if I were using this, so all in here seems like the best thing to me. |
Umm... I am a little confused. Do you mean "react-ujs.js" by "1 less dependency"? I would argue it is an existing practise in rails' The To ease developers' life, follow the common practise of other rails js/css gem, a rake task |
Oh I see. I didn't realize In that case, then I think it's fine to have 2 distinct lines in |
I have been playing around with your view helper and have one that implements server rendering via ExecJS, which is part of the Asset Pipeline in Rails so everyone should have it. It pulls in a file called https://github.com/johnthethird/react-rails/blob/server-rendering/lib/react/rails/view_helper.rb |
I thought it was gonna be much harder. |
Thanks for the feedback. The reason I wanted all the components in one JS is so that I could load it once into the JS VM and cache it, then whenever you need to render its just running the As far as getting data, why not get it in Ruby on the server and just pass it in? I suppose thats code duplication if you also want to do the same thing on the client. One idea would be to wrap the external data in a Rails API, and for server rendering you grab it directly from Ruby, and on the client you hit the API. Or, maybe you can run the HTTP GET from inside the JS VM in |
I think it's better to provide an option for filenames, like JS runtime like therubyracer doesn't have network support. But it's easy to workaround, get the data in Ruby code and pass it as a prop named like Anyway, I'd like to implement the ujs stuff first because both renderings can benifit. |
Im not sure what the advantage is to having it configurable. The helper needs all React components loaded in order to work, so convention over configuration here might make sense. You can always make I like @quark-zju unobtrusive idea, and took a crack at it here: Any |
About configurable filenames:
|
Sprockets is smart enough not to duplicate code with multiple |
* Implement react_ujs. * Replace inline scripts with react_ujs style data attributes. * Update tests and README.
Newer coffee-script generates slightly different output, accept it in JSX coffee script test case.
@johnthethird If @zpao react_ujs is now complete and this branch is probably ready to be merged. Could you take a look? |
} | ||
} | ||
handleEvent('page:load', mountReactComponents); | ||
handleEvent('page:before-change', unmountReactComponents); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This has potential for problems (if a component lives outside of the turbolinked node, or however that works), but I think this is fine for an initial version. But beware bug reports :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Turbolinks simply replaces entire body
in all cases. Components outside body
sounds strange. So I think it's okay. For DOM nodes created by script on the fly, they are not mounted by react_ujs. While jquery_ujs uses $.live
so it can handle dynamically created nodes. However, monitoring DOM changes is expensive. It's probably fine to let the user manually call React.renderComponent
on dynamically created nodes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My mistake. I assumed turbolinks let you operate on a more precise scale. I haven't actually upgraded anything to use it yet...
@johnthethird @JakubMal, would you be willing to do a once-over here? My brain is very much outside the rails world these days and would appreciate some help :) |
// Assume className is simple and can be found at top-level (window). | ||
// Fallback to eval to handle cases like 'My.React.ComponentName'. | ||
var constructor = window[className] || eval(className); | ||
var props = JSON.parse(node.getAttribute(PROPS_ATTR) || '{}'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can actually default to null
for the props (that's actually what we do in the JSX transform to avoid extra object allocations).
* react_ujs: use `null` instead of `{}` as default props. * view helper: remove 'data-react-props' if props is empty. * view helper: allow 'data' in HTML options.
This looks good to me. Nice work @quark-zju. When you pull this in I will toss over a PR for a server-rendering component which uses an object pool to allow multiple threads access to a pool of JS VMs with the React code preloaded. Seems to be working well in mri/jruby with puma/torquebox/trinidad (multi-threaded Rails app servers). |
This allows better minification.
@quark-zju @zpao Seems fine, but I'll take another look tomorrow. I just did a dumb take ours + take theirs rebase of this against my PR, and all tests passed. 👍 |
* Fix a comment about React.renderComponent where the order of arguments is wrong * Mention that react_ujs will unmount components and how to avoid it
👍 |
View helper to render react component
Let's discuss here and if you like the idea, we can talk about details and I will convert this issue into a PR.
To render a react component, currently it requires a
<div>
and a line of js callingReact.renderComponent
. Developers need also take care of JSON and div id, etc. This feels not elegant in Ruby world.Inspired by other helper method like
content_tag
,select_tag
etc. I think it may be a good idea to make one for react. So a developer can simply write this in view template:I have a proposed implement:
Future work could be: optionally use
React.renderComponentToString
to render initial html at server side.Thoughts?