UI-Router provides extremely flexible, state based routing to the React ecosystem.
Routing frameworks for SPAs update the browser's URL as the user navigates through the app. Conversely, this allows changes to the browser's URL to drive navigation through the app, thus allowing the user to create a bookmark to a location deep within the SPA.
UI-Router applications are modeled as a hierarchical tree of states. UI-Router provides a state machine to manage the transitions between those application states in a transaction-like manner.
The UI-Router package is distributed using npm, the node package manager.
yarn add @uirouter/react
Import UIRouter into your project, define some states and you're good to go!
importReactfrom'react';importReactDOMfrom'react-dom';import{UIRouter,UIView,pushStateLocationPlugin}from'@uirouter/react';importHomefrom'./components/Home';// define your statesconststates=[{name: 'home',url: '/home',component: Home,},];// select your pluginsconstplugins=[pushStateLocationPlugin];ReactDOM.render(<UIRouterplugins={plugins}states={states}><UIView/></UIRouter>,document.getElementById('root'),);
I used to do front-end with angular.js. And ui-router was just perfect for me. Because I had a good memory with ui-router in angular.js, I am trying to use ui-router in React too. However, it seems like the manual or documentation is very unfriendly for new people.
Now, I am trying to configure otherwise() function in react, but have no clue what am I supposed to do. Nothing is found in the official document and there are not many resources out there.
How does one go about defining a default landing route in ui-router-react, ie the state you wish to navigate to on something like http://localhost:8080?
When using ui-router-ng2 I did something like this....
but it doesn't seem to work the same, ie upon navigating to http://localhost:8080 the react router doesnt't navigate to the home state as I expected it--it does nothing but display the nav panel (which works fine when i start clicking on linkds)
Is there some way to effect the equivalent default state in the react version of ui-router?
We have been discussing whether to change the current UIView behaviour regarding the injected resolves in the routed component.
Problem:
Currently the UIView component wraps all the resolves into a single resolves prop that is injected in the routed component. This makes the routed component coupled to the router API, which renders it non reusable in other situations.
// state declarationconstmyState={url: '/',name: 'myState',component: MyComponent,resolve: [{token: 'someResolve',resolveFn: ()=>MyService.getSomeData()}]}// class componentclassMyComponentextendsComponent{render(){const{someResolve}=this.props.resolves;return(<p>Resolved is: {someResolve}</p>);}}// or function componentconstMyComponent=({ resolves })=><p>Resolved is: {resolves.someResolve}</p>;
Solution:
We were thinking about injecting the resolves as individual props, in order to decouple the component from the router API, especially when the component doesn't access the transition so it doesn't really need to know about the router at all.
// class componentclassMyComponentextendsComponent{render(){const{someResolve}=this.props;return(<p>Resolved is: {someResolve}</p>);}}// or function componentconstMyComponent=({ someResolve })=><p>Resolved is: {someResolve}</p>;
Thoughts:
The change in code would be trivial, but this would be a breaking change as every routed component must be updated accordingly (nothing too painful, but still a pita).
The other problem we see with this solution is the risk of props collision, especially with the transition props that is silently injected along with the resolves. This means the user has some restriction on what names can be used for the resolves, and it might be wise to add a warning in case of collision.
Ultimately we wanted to know what y'all think about this change, if you have incurred in any problem related to this and if you think you would benefit from this update. Please keep in mind that the current version is a pre-release and this would be the best time to implement such a breaking change, before hitting production-ready stable versions.
The UMD build looks for window.react instead of window.React as external library.
Also the lib is exported as window.ui-router-react and should be window.UIRouterReact instead.
As far as I can tell it's not being used and if I've missed something and is being imported somewhere, library still shouldn't modify global environment.
I just found out about a react implementation of ui-router and was playing around with it. The current version of ui-router-core from npm kept rendering setUrl error.
From urlRouter
UrlRouter.prototype.push = function (urlMatcher, params, options) {
var replace = options && !!options.replace;
$location.setUrl(urlMatcher.format(params || {}), replace);
};
Fixed it locally by changing setUrl to url. Thought I'd notify you awesome people here all as well. Thanks!
I burned a few hours attempting to fix an issue that was actually a side-effect of unintentionally calling start() on my router object twice โ once in my router.config file (inspired by the sample app,) and then once again by passing router to the UIRouter component.
The trouble is, it isn't particularly obvious that passing a UIRouterReact class to a UIRouter component (<UIRouter router={router}></UIRouter>) automatically calls the start() method on router.
Since I can't actually think of any reason why a user would choose to call router.start() twice in the same application, it may be prudent to throw an error if a user attempts to do so.
What works, is to explicitly define just the name, which is not very convenient for user, who is in the react component, because, he doesn't immediately know, that the create "new" is a child route
I am using axios for my http in RootService, so it simply returns axios.get('url')
then injecting my routes simply as
<UIRouter states={Routes} plugins={plugins}> <UIView/> </UIRouter>
The http fires and I can see it in my network in my web tools, if i place a loading component it even awaits for it until it resolves. nonetheless, the value of the resolve is not present in the props.resolves of the Page1 component.
I have red the documentation a couple of times and It does not seem I am missing anything.
Could you let me know what I might be doing odd?
It doesn't seem that props from UIView are passed on to the children except for a select few. Furthermore, the props that are passed are never updated in the children of UIView after they change. I request that properties propogate from UIView into their children and those children receive updates.
I am trying to create a reusable component that prepopulates ui-router states. For example, given an array of tabs and an array of drawers, generate the routes, views, with relative and absolute naming. This component would be an easy starting point for new users to ui-router and enable early complex routing.
Currently this is working but the component requires context and a state manager like Redux to get props to children of UIView and have changes propagate. For the component to be reusable, it'd be best if a state manager wasn't included and React component state was used instead.
I tried using context alone but context changes don't propogate. I am going to play with using callbacks in my context instead, but the cleaner and easier solution would be if UIView passed props and propogated changes to child components.
When wrapping the <UIView/> with <ReactCSSTransitionGroup/> the animation is not taking place, I think its related to the fact that when transitioning between states, the <UIView/> is not rerendered, only its children.
Any way to animate transitions?
Hi Marco,
first of all thank you for your work on UI Router framework.
I have two issues with new version (0.4.0) of React UI Router. Both are connected with config prop of UIRouter component:
First - there is a wrong config prop example using the old router.urlRouterProvider.otherwise (I think it should be router.urlRouter.otherwise(โฆ)).
Second - otherwise setting through config prop works only with hashLocationPlugin for me. It doesnโt work with the recommended pushStateLocationPlugin plugin. This plugin redirects the app to the desired url, but nothing else happens. BUT it works correct when I set otherwise through manual bootstraping, i.e.:
const router = new UIRouterReact()
...
router.urlRouter.otherwise("/client/list")
...
router.start()
After upgrading from 0.3.0 to 0.4.0, I am getting the following error message when using router.stateService.go(statename):
Failed to execute 'pushState' on 'History': A history state object with URL 'http://sales/' cannot be created in a document with origin 'http://localhost:8090' and URL 'http://localhost:8090/home'.
I still transition correctly to the state; but the url doesn't reflect. Navigating manually with the address also works.
The application works fine in browser, but when executing a simple test:
it('renders without crashing', () => {
const div = document.createElement('div');
ReactDOM.render(<Application />, div);
});
the test itself passes, but complains with
console.error node_modules/ui-router-core/lib/state/stateService.js:35
TypeError: Cannot read property 'getElementsByTagName' of undefined
at BrowserLocationConfig.Object.<anonymous>.BrowserLocationConfig.applyDocumentBaseHref (/Users/rattkin/Documents/Workspaces/WebStorm/project/node_modules/ui-router-core/lib/vanilla/browserLocationConfig.js:36:32)
at BrowserLocationConfig.Object.<anonymous>.BrowserLocationConfig.baseHref (/Users/rattkin/Documents/Workspaces/WebStorm/project/node_modules/ui-router-core/lib/vanilla/browserLocationConfig.js:33:94)
at UrlRouter.Object.<anonymous>.UrlRouter.href (/Users/rattkin/Documents/Workspaces/WebStorm/project/node_modules/ui-router-core/lib/url/urlRouter.js:186:66)
console.error node_modules/ui-router-core/lib/state/stateService.js:36
TypeError: Cannot read property 'getElementsByTagName' of undefined
at BrowserLocationConfig.Object.<anonymous>.BrowserLocationConfig.applyDocumentBaseHref (/Users/rattkin/Documents/Workspaces/WebStorm/project/node_modules/ui-router-core/lib/vanilla/browserLocationConfig.js:36:32)
at BrowserLocationConfig.Object.<anonymous>.BrowserLocationConfig.baseHref (/Users/rattkin/Documents/Workspaces/WebStorm/project/node_modules/ui-router-core/lib/vanilla/browserLocationConfig.js:33:94)
at UrlRouter.Object.<anonymous>.UrlRouter.href (/Users/rattkin/Documents/Workspaces/WebStorm/project/node_modules/ui-router-core/lib/url/urlRouter.js:186:66)
I'm testing using the standard "npm test" from react-create-app.
Seems like there is an issue with providing base href. Since I'm testing component and not whole index (where the base usually is), it has a problem.
onSuccess is registered in the Parent component's constructor and fires as expected. I am also successfully retrieving sampleMember from the params().
However, setState is consistently aborted by React due to the component's _reactInternalInstance member being undefined. setState calls enqueueSetState and enqueueCallback which both fail (noop) if this._reactInternalInstance is falsey.
I am using this same pattern in an Angular version of this sample application (with UI Router) and it works as expected. Am I missing something here, or is this a legitimate bug?
So that user get's notified about missing dependency during npm install. It is unlikely someone will install this without react, but you never know.. :)
Thanks so much for the port to ReactJs! Cannot imagine routing without ui-router.
I've spent many years using UI-Router with Angular, now I have moved to react, and am using the port. I know we can make multiple views in angular via
and then defining views:{ 'myView':{component:myComponent} }.
Wondering how to do this in React? I went through the docs and examples, and did not see it. Totally could have been me missing it though. Thanks again!
I believe the current syntax is too verbose for common cases, so I'd like to propose either adding alternative API or merging both into single component.
I have this state definition: const routerState = { name: 'router', url: '/sign-router?event', component: SignRouter }; const router = new UIRouterReact(); router.urlRouterProvider.otherwise('/'); router.stateRegistry.register(routerState); router.start();
event should be a state param defined in the url as a query param but trying for example http://localhost:8080/#/sign-router?event=ttl_expired the state component get the following values in the props.resolves: resolves: { $stateParams: { #: null, event: undefined },... }
Am I missing any state param configuration for query params? If use the /route/:param notation works but not with query params notation.
For some reason the UISrefActive components never render active as a class for the UISref components. Does this have something to do with the hashLocationPlugin? Or did I set something up wrong?
Setup
Imports
import {UIRouter, UIView, UISref, UISrefActive, hashLocationPlugin} from 'ui-router-react'
I have reading the Docs on how to go back to previous State/page visited, but I don't find anything in the docs, please if you could point me the right direction that would be great
We are having trouble getting the UISrefActive to work in 0.4.0 because it's indicating class is not being supplied. We've marked it up the following ways:
Warning: Failed prop type: The prop `class` is marked as required in `UISrefActive`, but its value is `undefined`.
in UISrefActive
in Unknown (created by Unknown)
in div (created by Unknown)
in Unknown (created by AppModulesContainer)
in div (created by AppModulesContainer)
in div (created by AppModulesContainer)
in AppModulesContainer (created by Connect(AppModulesContainer))
in Connect(AppModulesContainer) (created by Reporting)
in div (created by Reporting)
in div (created by Reporting)
in div (created by Reporting)
in div (created by Reporting)
in div (created by Reporting)
in div (created by Reporting)
in div (created by Reporting)
in div (created by Reporting)
in div (created by Reporting)
in div (created by Reporting)
in Reporting
in UIRouter
in Provider
Is it possible with the new API, to add transition service hooks to the UIRouter component via props (like plugins, state, config) or do I need to bootstrap manually?
{
name: 'home',
url: '/',
component: DashboardContainer,
resolve: [
{
token: 'currentUser',
resolveFn: () => store.dispatch(getCurrentUser())
.then(res => {
if (!res.value) {
throw new Error('The current user could not be identified.');
}
// debugger;
})
.catch(err => {
// debugger;
})
}
],
onEnter: () => {
// debugger;
},
onExit: () => {
// debugger;
}
},
The getCurrentUser action looks like this:
return {
type: GET_CURRENT_USER,
payload: ax.request({
url: urlJoin(
config.portal.url,
'api/CommonApi/GetCurrentUser'
),
method: 'get',
maxRedirects: 0
}).then(res => {
// debugger;
if (!(res.data && res.data.clientId)) {
throw new Error('The current user could not be identified.');
}
}).catch(err => {
console.warn(err);
})
};
When walking through this transition, I get to the debugger in the getCurrentUser action and throw the Error because we didn't get the user back. This then executes the console.warn(err). Then it executes the then of the store.dispatch promise, which subsequently bubbles that error and hits the debugger in the catch of the store.dispatch promise.
However, even though the promise is being failed, the onEnter is still firing for this state and the state is being rendered; what I'd like to do is navigate to the Login state.
I have been trying to use ui-router-react but can not get past webpack complaints for some reason.
ERROR in [at-loader] node_modules/ui-router-core/lib/common/common.d.ts:388:31
TS7006: Parameter 'a' implicitly has an 'any' type.
ERROR in [at-loader] node_modules/ui-router-core/lib/common/common.d.ts:388:34
TS7006: Parameter 'b' implicitly has an 'any' type.
ERROR in [at-loader] node_modules/ui-router-core/lib/resolve/resolveContext.d.ts:7:22
TS7005: Variable 'NATIVE_INJECTOR_TOKEN' implicitly has an 'any' type.
ERROR in [at-loader] node_modules/ui-router-core/lib/transition/transitionHook.d.ts:13:37
TS7006: Parameter 'error' implicitly has an 'any' type.
ERROR in [at-loader] src/components/loginComponent.tsx:23:33
TS2314: Generic type 'KeyboardEvent' requires 1 type argument(s).
ERROR in [at-loader] src/components/loginComponent.tsx:32:31
TS2314: Generic type 'KeyboardEvent' requires 1 type argument(s).
These errors (besides last two) only happen when I try to import
import {UIRouter, UIView, UISref, UISrefActive, pushStateLocationPlugin} from 'ui-router-react';
so I can use it for my ReactClass or Stateless component like this:
import*asReactfrom'react';import{Component,DOMAttributes}from'react';import{InjectedProps}from'ui-router-react';interfaceFooContainerPropsextendsInjectedProps<any>,DOMAttributes<any>{}interfaceFooContainerState{}classFooContainerextendsComponent<FooContainerProps,FooContainerState>{render(){const{transition}=this.props;const{what='awesome'}=transition.params();return<div>UIRouter is {what}!</div>;
}}
It must be very stupid question but I wasn't able to find any sound solution to my question on the web. So I am posting it if I can get help from here.
Basically I want to make nested views. I was able to make nested views. However, I have no idea how to pass parent's state to nested view's component.
I tried below but didin't work
<UIView user={this.state.user}/>
Also, I am curious how parent and child (or nested) views acually communicate in ui-router. Do they follow the typical data flow in react.js? For example, usually I make functions and save data to state in container component (parent) and pass to children component. So technically child components emit events and parent do the actual work responding to the emitted events.
First of all, let me congratulate and thank you on your awesome work on the UI-Router port.
I worked with Angular 1.x for few years and UI-router was my "go to" router, and coming to React I found React router to be a pretty cheap router implementation (unstable API, routes bound to URL instead of state, etc), but it seems to be the most used by the community.
I believe UI-Router has the potential to do for the React community what it did for the Angular community, but it really needs better documentation and well written tutorials to encourage people to start using it. I almost gave up on UI-Router because I couldn't find a way to programmatically changing the state, it doesn't say anywhere that the "transition" object is passed to the route's component as a prop.
The fact that lot's of the React wrapper docs point to the core router docs doesn't help a lot, as I believe that kills the purpose of having a react wrapper that abstracts ui-router to work in a "react way".
Please don't take any of this as criticism, its just a feedback as I'd really love to see ui-router as the "default" routing solution for React. And again, congrats on the outstanding work on wrapping UI-Router for React, and please let me know if there's anything I can help with.
I am trying to implement ui-router into my react/typescript application (bundling with webpack). I am getting warnings during the bundle on missing *.ts files.
For example: WARNING in ./~/@uirouter/core/lib/hooks/ignoredTransition.js (Emitted value instead of an instance of Error) Cannot find source file '../../src/hooks/ignoredTransition.ts': Error: Can't resolve '../../src/hooks/ignoredTransition.ts'
I check the node_modules and I do not see the ts files in path. Is there something that I am missing?
My default state route has a resolve that gets the name of the users default report (view). How can I use the result of that resolve to redirectTo: ?
I see this from the API:
// a fn returning a promise for a redirect.state('G',{redirectTo: (trans)=>{letsvc=trans.injector().get('SomeAsyncService')letpromise=svc.getAsyncRedirectTo(trans.params.foo);returnpromise;}})
but in this react version... I don't think getAsyncRedirectTo is available... or if it is, I'm not finding it.
and now that I recheck let svc = trans.injector().get('MyService') does not return either. Thows error: Error: Resolvable async .get() not complete:"MyService"
and the class="active" state is taking into account the params, in order to set the class as active.
how can I do so that the class is always active irrespective of the parameters given as a default, so in essence be active as long as the state is in the dynamicView path
When attempting to bundle a React app that uses ui-router-react I get a zillion complaints from Rollup along the lines of
Error: Cannot call a namespace ('classNames')
Based on similar errors I see documented for Rollup...
When importing a module's namespace using * as foo you get a namespace object which isn't callable. You should import default export instead.
import express from 'express';
const app = express();
Please help to solve a trivial issue: how should I programatically navigate to a certain route? For example, when user clicks a button on login form, after the form is validated, we move user to /home route.
Side note: I think it will also be very helpful to include into an official tutorial. Existing examples are only showing how to work with <UISref> elements to navigate.
So far, the way that I found is by injecting$transition$ into a resolve() function, then saving transition to a property of target component, then getting router instance from there. So the code looks like this:
// to get the router
const loginState = {
name: 'login',
url: '/',
component: Login,
resolve: [{
token: 'router',
deps: ['$transition$'],
resolveFn: (trans) => trans.router
}]
};
// then inside of <Login> component:
onSubmit(e) {
e.preventDefault();
this.router.stateService.go('student');
}
This code is working but it looks ugly. I'm sure there's a better way :)
With React being very very component based. How do I transition from one state to another?
I am seeing calling transition.router.stateService.target or .go but that is only accessible from the parent state. Not accessible from the child components that are building that parent state.
I'd like to discuss a bit what could be a great Redux integration with UI-Router.
NB: There is nothing preventing you from using Redux in combination with the router right now, as you can simply connect() your "state component" and that's it.
There are some features that I think might be useful:
sync the url location in the redux store whenever changes
trigger navigation via redux actions
I'm not a time-travel user so I honestly don't know how many people rely on it but I think it could be supported if it makes sense.
Will you provider a feature just like sticky-state or react-keeper or Vuejs's keep-alive .
I'm using ng1 with uirouter-extra-state in my mobile's App and prepend migrates to react .
Thanks your work !
how to redirect to home page when enter index app . just like this :
127.0.0.1:8090 to 127.0.0.1:8090/home
when i directly enter 127.0.0.1:8090/home . every thing working good .
I just read docs ( i'm using "@uirouter/react": "^0.5.0" now ) and can not resolve this problem .