I am creating a blog using React/React-Router/Redux, and depending on the location, I want to show different blog posts, so if you are on /category/cat1 you don't have the same list of blogs than if you are on /category/cat2.
So I'm thinking on storing the blog list in the store and my react component would pick it up from there so I could just have actions updating my state.
My thinking is listening on the browserHistory so I can get when the location changes and trigger the action which would update the new blog list, but I can't find how to get the params from my location path like I would from my component props /category/:catName
How can I get those params?
Is it actually the way to do it or should I use a different approach?
Thanks.
From the version 2.0.0 upgrade guide:
RoutingContext -> Router render prop
You can now pass a render prop to Router for it to use for rendering.
This allows you to create "middleware components" that participate in
routing. Its critical for integrations with libraries like Relay,
Redux, Resolver, Transmit, Async Props, etc.
The default is basically this:
<Router render={props => <RouterContext {...props} />} />
This render prop on the Router is a hook into the render stage, and those props that are passed to the function contain the parsed route params, as well as lots of other routing context. Just make sure your function returns a RouterContext, or some equivalent, in the end.
Related
I am using redux-observable and in my epics I am changing the route in some of them using browserHistory.push. Is this standard/good practice? my gut feeling tells no, however need your opinion. In addition to this after upgrading to react-router 4, I cannot get access to browserHistory how do I do this?
Imperatively calling browserHistory.push() is totally fine. If it works for your use case and you don't need to know about the route changes in your reducers, carry on!
That said, the "purist" way would be for your epic to emit an action that will cause the route change. This can be done in react-router v4 by using the new react-router-redux, which supersedes the old one with the same name.
Once added, you can use the provided actions creators:
import { push } from 'react-router-redux';
export const somethingEpic = action$ =>
action$.ofType(SOMETHING)
.switchMap(() => {
somethingLikeAjaxOrWhatever()
.mergeMap(response => Observable.of(
somethingFulfilled(response),
push('/success-page')
))
});
To be clear, push() replace() etc in react-router-redux are action creators--aka action factories. They don't actually cause the route change themselves, or perform any side effects at all. They return an action that needs to be dispatched somehow for the route to change.
The other benefit of using actions to signal route change intents is testability. You no longer have to mock a history API, you can just assert that the epic emits the expected action. This is known as "effects as data", since your code doesn't perform the actual side effect, you just generate the intent.
I'm loving v4 but in 4.1.2 this keeps tripping me up when using the browser router:
With a component in a Route component I have these props passed in: {computedMatch, location, path} although the documentation tells me to expect {match, location, history} which is what I get with the hash router.
To get the history passed in I have to use the withRouter wrapper which feels very clunky because the relevant component is the component prop to a Route component.
The documentation sounds right to me. Is this a bug?
You can get access to {match, location, history} if you use Route as
<Route path="/" component={myComponent}
In above code you will have match location and history accessible inside myComponent.
Or else you have to use withRouter
My use case: application has a header that displays current user's name. This header is the same on all pages.
User data is loaded from JSON API into the Store when user logs in.
Now, how am I supposed to access this data from Store to use it on every page?
One option is to pass it from routes:
{{app-header user=model}}
But then I would have to use the same model in all the routes and also would be unable to use any other? How can a (supposedly reusable) component expect from me to adjust every route to its data structure?
The other option is that component always loads data from Store on its own, but this seems strongly unrecommended and actually very hard to do for me without any proper guide. I managed to discover service injection method (store: Ember.inject.service() in the component) but still can't get the component to properly display data from store in the template.
When I use:
name: () => {
return this.store.peekRecord('user', 1).get('name');
}
then {{name}} in template renders function definition, not what it returns.
When I use:
name: Ember.computed(() => {
return this.store.peekRecord('user', 1).get('name');
})
then {{name}} renders: <!---->
Could you please explain what is a good way to do this? Is there some "master model" defined in application.js besides models from routes? Should I really pass the same data to component in every route? Any information or suggestions will be greatly appreciated.
You could try using a service (guide here).
// app/services/store.js
import DS from 'ember-data';
export default DS.Store.extend({});
// app/services/user-service.js
import Ember from 'ember';
export default Ember.Service.extend({
store: Ember.inject.service(),
user: Ember.computed(function() {
return this.get('store').findRecord('user', ':id');
})
});
Then, in all your other components, controllers, and routes, you can access the service.
// Inside a controller
export default Ember.controller.extend({
userService: Ember.inject.service(),
firstName: Ember.computed.alias('userService.user.firstName')
});
The first name, or even the user object itself is now available in you template.
{{userService.user.firstName}}
OR
{{firstName}}
First approach, (Keeping it in Application Route)
1.Define it in application route model hook - refer multiple modelsin single route.(https://guides.emberjs.com/v2.9.0/routing/specifying-a-routes-model/#toc_multiple-models)
2.If its required in another route, then you can access already resolved model of the parent route through modelFor method.(http://emberjs.com/api/classes/Ember.Route.html#method_modelFor)
Second Approach, (Service)
Like #devman answer, you can load it in service and inject and get it wherever you require.
userService:Ember.inject.service();
name: Ember.computed.alias('userService.name')
Is this outdated? https://github.com/rackt/react-router/blob/95094769caca201b8e9afe68ff3d6cb4ff280fac/docs/advanced/NavigatingOutsideOfComponents.md
I can't seem to get it working.
I'm exporting the history object like this:
export const history = require('history/lib/createBrowserHistory')();
And then I'm using it like so:
history.push('/home');
But the page doesn't change, only the URL changes.
This functionality still works fine and the current docs still have it in master
Notice the extra () at the end of the require in your code. That's a function call which returns a new history object instance.
In that doc they do the function call once in history.js and export the instance. They then require history.js and used that instance for both the router and outside of the router.
I have designed a webpage with a single portlet.
I want to pass parameters to this portlet.
So I am calling my webpage this way (on a local liferay instance):
http://localhost:8080/group//?param=1
To avoid misunderstandings, I am not just trying to pass parameters between pages of a portlet (controller to view). I know how to do this and it works fine.
In this case I am trying to start my portlet with parameters from the URL hosting it.
My understanding from the docs is that the portlet is not able to access the URL parameters
The advised solution that I read about was to use "friendly-url-mapper".
I did not manage to get it to work. Here is what I did so far:
I added into liferay-portlet.xml:
<friendly-url-mapper-class>com.liferay.portal.kernel.portlet.DefaultFriendlyURLMapper</friendly-url-mapper-class>
<friendly-url-mapping>view</friendly-url-mapping>
<friendly-url-routes>friendly-url-routes-for-parameters.xml</friendly-url-routes>
Is view the correct value to set? Real doubt about it.
I created friendly-url-routes-for-parameters.xml with this content:
<routes>
<route>
<pattern>/result?{match}</pattern>
<implicit-parameter name="param">{match}</implicit-parameter>
</route>
</routes>
/result is mapped to a result.jsp page into my controller class (this part works):
I would expect that :
http://localhost:8080/group//?param=
and / or
http://localhost:8080/group///-/view/?param=
would redirect to my result.jsp with the ?param= parameter.
What did I not understand correctly?
Ok you can and you can't but basically you shouldn't, but I'm no one to tell you what you should and shouldn't do .
What you should do to get this parameter is get hold of the original servlet
HttpServletRequest httpReq = PortalUtil.getOriginalServletRequest(PortalUtil.getHttpServletRequest(req));
Then you can simply get the parameter you wish by using the getParameter
method
String myParam = httpReq.getParameter("param");
Hope this helps