-
-
Notifications
You must be signed in to change notification settings - Fork 631
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
Providing rails_context always to generator functions (store and component) #345
Conversation
My gut tells me to make extra params an object, and leave the first param as the props object, for the JS code. Otherwise, people would have to update their JS app components. They still might have to if they were using the location 2nd param, but that's unlikely to be many people. |
👍
It's needed for react-router on server, so we shouldn't rely on props from user here.
Seems fine.
If |
@alexfedoseev Given that file with this, how do we inject the current location? /**
* This action type will be dispatched when your history
* receives a location change.
*/
export const LOCATION_CHANGE = '@@router/LOCATION_CHANGE'
const initialState = {
locationBeforeTransitions: null
}
/**
* This reducer will update the state with the most recent location history
* has transitioned to. This may not be in sync with the router, particularly
* if you have asynchronously-loaded routes, so reading from and relying on
* this state it is discouraged.
*/
export function routerReducer(state = initialState, { type, payload }) {
if (type === LOCATION_CHANGE) {
return { ...state, locationBeforeTransitions: payload }
}
return state
} |
maybe I return for the extra values: { location: { href, pathname, hash, search } } |
@justin808 I like it as an object as the second variable with all of the location data. Not sure on a string of the full url vs the object. I feel like people are used to parsing urls but generally they get it from window that parses it kinda for them, so I could see it being nice broken up like that. I'd say object is fine for now. @alexfedoseev what do you think about string vs object? |
Debating on whether or not to pass the location parts, as this library is very popular: https://www.npmjs.com/package/url-parse (550k downloads the past month). def rails_context
uri = URI.parse(request.original_url)
# uri = URI("http://foo.com/posts?id=30&limit=5#time=1305298413")
result = {
# URL settings
location: request.original_url,
scheme: uri.scheme, # http
host: url.host, # foo.com
pathname: uri.path, # /posts
search: uri.query, # id=30&limit=5
hash: uri.fragment, # "time=1305298413"
# Locale settings
i18nLocale: I18n.locale,
i18nDefaultLocale: I18n.default_locale,
httpAcceptLanguage: request.env['HTTP_ACCEPT_LANGUAGE']
}
if ReactOnRails.configuration.rendering_extension
custom_context = ReactOnRails.configuration.rendering_extension.custom_context(self)
if custom_context
result.merge!(custom_context)
end
end
result
end This can set the locale quite nicely: https://github.com/iain/http_accept_language. I'm considering allowing a RenderingExtension like this: Set the class for the config.rendering_extension = RenderingExtension Implement it like this: module RenderingExtension
# Return a Hash that contains custom values from the view context that will get passed to
# all calls to react_component and redux_store for rendering
def self.custom_context(view_context)
{
somethingUseful: view_context.session[:something_useful]
}
end
end This would put a prop of Since you can't access the rails session from JavaScript (or other values available in the view rendering context), this might useful. So why not put this in props? The advantage to the Feedback? |
@alexfedoseev @martyphee @jbhatab This is ready to merge once I add tests for the new functionality. The work on the view helper and the JS libraries should be complete, as well as to the /spec/dummy sample app. Any comments on the API? I hope to merge this to master on Saturday! |
@justin808 I think the api for the RenderingExtension thing is a bit odd. The concept is fine for flexibility. Can we just have extra params that are passed in on the helper calls get passed in automatically? Like a wildcard args situation. |
Review status: 0 of 21 files reviewed at latest revision, 25 unresolved discussions. app/helpers/react_on_rails_helper.rb, line 149 [r3] (raw file): app/helpers/react_on_rails_helper.rb, line 172 [r3] (raw file): app/helpers/react_on_rails_helper.rb, line 242 [r3] (raw file): app/helpers/react_on_rails_helper.rb, line 255 [r3] (raw file): app/helpers/react_on_rails_helper.rb, line 291 [r3] (raw file): app/helpers/react_on_rails_helper.rb, line 348 [r3] (raw file): node_package/src/clientStartup.js, line 35 [r3] (raw file): node_package/src/clientStartup.js, line 51 [r3] (raw file): node_package/src/clientStartup.js, line 73 [r3] (raw file): node_package/src/clientStartup.js, line 106 [r3] (raw file): node_package/src/createReactElement.js, line 25 [r3] (raw file): I'll have to experiment to see if this is overkill. node_package/src/createReactElement.js, line 33 [r3] (raw file): BREAKING CHANGE RIGHT HEREYes, going from a string to an object. CC: @jbhatab, @thewoolleyman, @martyphee, @alexfedoseev spec/dummy/app/controllers/pages_controller.rb, line 5 [r3] (raw file): spec/dummy/client/app/components/HelloWorld.jsx, line 14 [r3] (raw file): spec/dummy/client/app/components/HelloWorld.jsx, line 57 [r3] (raw file): spec/dummy/client/app/components/HelloWorldContainer.jsx, line 9 [r3] (raw file): spec/dummy/client/app/components/HelloWorldContainer.jsx, line 23 [r3] (raw file): spec/dummy/client/app/components/HelloWorldRedux.jsx, line 10 [r3] (raw file): spec/dummy/client/app/components/RailsContext.jsx, line 1 [r3] (raw file): spec/dummy/client/app/reducers/RailsContextReducer.jsx, line 1 [r3] (raw file): spec/dummy/client/app/reducers/reducersIndex.jsx, line 8 [r3] (raw file): spec/dummy/client/app/startup/ClientReduxApp.jsx, line 20 [r3] (raw file): Sort of interesting that we slam the param in, and then make it its own "reducer domain". Maybe there's a better pattern since the the rails_context really is immutable? spec/dummy/client/app/startup/ServerReduxApp.jsx, line 21 [r3] (raw file): spec/dummy/client/app/startup/ServerRouterApp.jsx, line 11 [r3] (raw file): spec/dummy/config/initializers/react_on_rails.rb, line 9 [r3] (raw file): Comments from the review on Reviewable.io |
@jbhatab You already have props for that. So I don't understand your use case. Review status: 0 of 21 files reviewed at latest revision, 25 unresolved discussions. Comments from the review on Reviewable.io |
AFAIK, my only remaining task on this PR is to update the /spec/dummy tests to confirm the values in the displayed table. Review status: 0 of 21 files reviewed at latest revision, 25 unresolved discussions. Comments from the review on Reviewable.io |
Reviewed 13 of 17 files at r2, 4 of 5 files at r3, 4 of 5 files at r4. app/helpers/react_on_rails_helper.rb, line 348 [r3] (raw file): spec/dummy/client/app/components/HelloWorldContainer.jsx, line 9 [r3] (raw file): spec/dummy/client/app/reducers/RailsContextReducer.jsx, line 1 [r3] (raw file): spec/dummy/client/app/startup/ClientReduxApp.jsx, line 20 [r3] (raw file): spec/dummy/client/app/startup/ServerReduxApp.jsx, line 21 [r3] (raw file): Comments from the review on Reviewable.io |
Review status: all files reviewed at latest revision, 25 unresolved discussions. spec/dummy/client/app/startup/ClientReduxApp.jsx, line 20 [r3] (raw file): export default (props, railsContext) => {
const combinedReducer = combineReducers(reducers);
const combinedProps = Object.assign({}, props, railsContext);
const store = applyMiddleware(middleware)(createStore)(combinedReducer, combinedProps); Comments from the review on Reviewable.io |
Thanks Alex! Review status: all files reviewed at latest revision, 22 unresolved discussions. spec/dummy/client/app/startup/ServerReduxApp.jsx, line 21 [r3] (raw file): Comments from the review on Reviewable.io |
1141ac7
to
b06819d
Compare
Review status: 19 of 24 files reviewed at latest revision, 24 unresolved discussions. spec/dummy/spec/features/rails_context_spec.rb, line 1 [r5] (raw file): spec/dummy/spec/requests/server_render_check_spec.rb, line 61 [r5] (raw file): Comments from the review on Reviewable.io |
995857b
to
3834945
Compare
* Added configuration rendering_extension * added railsContext being passed to component and store generator functions. Contains values: key value href: http://localhost:3000/server_side_redux_app?ab=cd location: /server_side_redux_app?ab=cd (what react-router wants) scheme: http host: localhost pathname: /server_side_redux_app search: i18nLocale: en i18nDefaultLocale: en httpAcceptLanguage: en-US,en;q=0.8 and any values from the rendering_extension
3834945
to
0a09b81
Compare
Sorry for the late response. This won’t solve our current needs. We still need a way load the proper i18n file for server side rendering. |
@martyphee you can't pass the locale file into with this? |
Maybe. Right now we're depending on a global Jed is initialized like so in the i18n file being downloaded by the client.
|
@martyphee, @jbhatab You should be able to put these localization setups in separate files using the locale name in the file name (or as the whole file name). Then just do a require (not an import) based on the file appropriate for the locale. Since we cache the "context" of the whole server bundle file, this might be slightly more performant. Any reason that won't work? |
The translations are needed for server rendering of the React component. Somehow I have to have I might be looking at this again very soon. Looks like it's falling on me to rewrite a large portion of the site. |
Background:
As of v4, we provide the location as a second param to component generator functions after props, and ONLY on the server rendering. This is not in the current API for store generator functions.
Use Case
Needing the current url path for server rendering
Suppose you want to display a nav bar with the current navigation link highlighted by the URL. When you server render the code, you will need to know the current URL/path if that is what you want your logic to be based on. This could be added to props, or ReactOnRails can add this automatically as another param to the generator function (or maybe an additional object, where we'll consider other additional bits of system info from Rails, like maybe the locale, later).
Needing the I18n.locale
Suppose you want to server render your react components with a the current Rails locale. We need to pass the I18n.locale to the view rendering.
Details
We'll do a breaking change of changing the 2nd parameter from a string to an object, but this should affect very few users, as we only passed this for server rendering.
The new api will be to pass 2 params when generating React components or hydrating redux stores:
So if you register
MyAppComponent
, it will get called like:and for a store:
The
railsContext
may have:Additionally, you can customize the values.
Set the class for the
rendering_extension
Implement it like this:
This would put a prop of
somethingUseful
in the railsContext passed to all react_component and redux_store calls.Since you can't access the rails session from JavaScript (or other values available in the view rendering context), this might useful.
This change is