winoteam / react-router-navigation Goto Github PK
View Code? Open in Web Editor NEW⛵️ A complete navigation library for React Native, React DOM and React Router
License: MIT License
⛵️ A complete navigation library for React Native, React DOM and React Router
License: MIT License
Given the following:
const Root = (): React$Element<any> => (
<Provider store={store}>
<ConnectedRouter history={history}>
<DeepLinking>
<View style={styles.container}>
<StatusBar />
<Navigation>
<Card exact path="/" render={() => <IndexScene />} title={'Index'} />
<Card
exact
path="/a"
render={() => <AScene />}
title={'A screen'}
/>
<Card
exact
path="/b"
render={() => <BScene />}
title={'B screen'}
/>
</Navigation>
</View>
</DeepLinking>
</ConnectedRouter>
</Provider>
);
if i try to route from screen /b
to index /
using:
<Link component={TouchableOpacity} to={'/'} replace>
<Text>Back to index</Text>
</Link>
I'm getting:
What am i doing wrong here?
Great job on integrating react-router v4 into a feature navigation library.
If you go to the Huge example, click on Feed, click on an Item, click Next Item (3x), then swipe back 3x, you will see the back arrow in the Item header that can be pressed 3x to take you back (but this actually doesn't do anything since there is no where to go back).
Now repeat, but this time use the back button instead of swiping back. You'll see that the back button disappears because it recognizes you have gone back all the way.
Also, if you hit the search tab, the search text is in the status bar.
I with react-router i had a routing component made like so
<NativeRouter>
<AndroidBackButton>
<View style={{ flex: 1 }}>
<Route exact path="/" component={DashBoard} />
<Route exact path="/activity/:id" component={Activity} />
<Route exact path="/detail/:type/:id" component={Detail} />
...
</View>
</AndroidBackButton>
</NativeRouter>
and i tried implementing RRN like so (is this correct ?)
<NativeRouter>
<AndroidBackButton>
<Navigation navBarStyle={{ backgroundColor: colors.lightBlue[500] }} titleStyle={{ color: 'white' }} backButtonStyle={{ color: 'white' }}>
<Card exact path="/" component={DashBoard} title="Dashboard" />
<Card exact path="/activity/:id" component={Activity} />
<Card exact path="/detail/:type/:id" component={Detail} />
...
</Navigation>
</AndroidBackButton>
</NativeRouter>
in the first example the navbar is a plain view and so each component (Dashboard
, Activity
, Detail
) has a NavBar
components and controls things like title, color, buttons with props
I was wandering how could I maintain the same level of control, if possible, i had before
Every route change causes multiple (3-4) renders in a row for each mounted tab (I use the lazy mode) in BottomNavigation, including inactive ones. Needless to say it causes major performance problems.
Currently I use a little workaround when render each tab:
export default ({match, history, path}) => {
if (match == null || !history.location.pathname.startsWith(path)) return null;
return (
<Navigation>
// ...
</Navigation>
);
};
However I believe the issue is most likely goes down deeper to excessive History rerenders. Can something be done about it?
Hi everyone!
It’s been a very long time since I’ve been active on this repo. I’ve been really (really really) busy this whole year. I offer my humblest apologies for the unanswered issues and all your great PRs that have not been reviewed yet. But everything will be back to normal really soon, I promise.
I take this opportunity to share with you my thoughts about the future of the library, and especially the long-awaited v2. I don't want to give you any ETA yet, but be ready to get your hands on the alpha rather sooner than later! As a matter of fact, this matches with some technical needs inside my company, so you can expect a sustained development over the next few months.
Initially, this library wasn't meant to bring anything completely groundbreaking. It only allows you to combine the best of react-router@v4
- that offers an incredible API - with react-navigation
, another library which offers lots of components for mobile app navigation.
One of the major problems of react-router-navigation is that it was initially developed as an experiment and I decided to publish it without thinking that it could exceed these 200 stars. So: my deepest apologises for never really taking the time to think about the evolution of this library. But this should end now. The upcoming v2 should allow a more user-friendly usage and cover a wider range of applications, without changing its API.
The main points of this new version are:
react-native
or react-navigation
would not endanger the proper functioning of the library. It should doable through simple unit tests with Jest, and E2E tests with Detox.<Modal />
component and a <Drawer />
component.react-native-navigation
. This feature is part of an internal need at my company, that I would like to share with many people as possible. If some of you are interested, chime in! We have some great things to do together.A stable v1 should be available in a few months. There are still a few issues to fix and updates of react-native
, flow
and react-navigation
to operate.
I now give you the stage so that you can tell me your desires for this v2, just to be sure I haven't forget anything. I'm also interested in knowing how you use the library on a daily basis. Do you use it on iOS? Android? In production? In which company ? This will allow me to better understand how you use this library in order to guide its development towards the best possible path.
Stay tuned! 😊
Here it is, the roadmap for react-router-navigation
1.0 :
Hey,
first of all - thank you for maintaining this repo.
Using the first example of the Readme produced the following error:
const App = () => ( <NativeRouter> <Navigation> <Card exact path="/" render={() => <Link to="/hello"><Text>Press it</Text></Link>} /> <Card path="/hello" render={() => <Text>Hello</Text>} /> </Navigation> </NativeRouter> )
React.Children.only expected to receive a single React element child.
Changing this line:
render={() => <Link to="/hello">Press it</Link>}
to this:
render={() => <Link to="/hello"><Text>Press it</Text></Link>}
resolves the error and renders the cards.
Greetings from Hamburg
I'm trying to get the tab example to work, but nothing renders.
If I change the path to anything other that '/', it errors with "No initial route found".
Is there any better documentation of how the Tab bar works?
const Beer = () => {
return (
<View style={{ justifyContent: 'center' }}>
<Text style={{ fontSize: 40 }}>BEER</Text>
</View>
)
}
const Coffee = () => {
return (
<View style={{ justifyContent: 'center' }}>
<Text style={{ fontSize: 40 }}>Coffee</Text>
</View>
)
}
class HomePage extends Component<ReduxProps & ReduxDispatchProps & ReactProps & RouteComponentProps<any>, any> {
render() {
return (
<View>
<Tabs
labelStyle={{ color: 'white' }}
tabBarStyle={{ backgroundColor: 'purple' }}
tabBarIndicatorStyle={{ backgroundColor: 'white' }}
>
<Tab path="/" component={Beer} />
<Tab path="/coffee" component={Coffee} />
</Tabs>
</View>
)
}
}
Is there any way to force left button to appear? My use case is something like the following
I have a set of Routes
// App.js
<NativeRouter>
<Switch>
<Route path="/app/wizard component={Wizard} />
<Route exact path="/app" component={MainNavigation} />
</Switch>
</NativeRouter>
And then inside my Wizard component file
// Wizard.js
import { HeaderBackButton } from 'react-navigation';
class Wizard extends React.Component<Props, State> {
renderLeftButton = () => <HeaderBackButton onPress={this.props.history.goBack} />;
render() {
const { history } = this.props;
return (
<Navigation renderLeftButton={this.renderLeftButton}>
<Card exact path="/app/wizard" component={Step1} />
<Card path="/app/wizard/step-2" component={Step2} />
</Navigation>
);
}
}
Notice that in my Wizard component, I have to pass a custom renderLeftButton function, and this is ok, but I was wondering if it's possible to force the rendering of the back button whitout doing something like this? I checked the code and I found this line, but the scene.index === 0
does not work for all use cases I think?
history.goBack
🖖 ! This is a recurrent bug I used to have on iOS and (way more) on Android. Basically this screen would pop out when you navigate to a certain path and then use history.goBack()
:
Here are the routes I followed the get there:
/app/home
(when the app launches)/search/results
(after a search from the home screen)/app/place/{id}
(after selecting a place from the results screen)And the error occurred when I try to navigate back from this 3rd screen. I tracked down to bug until there: https://github.com/LeoLeBras/react-router-navigation/blob/master/modules/CardStack.js#L82, where this.props
was no longer available.
So what I did was log this.props
in componentWillMount
and this was the output:
As you can see: in this.props.history.location.pathname
, I do have my /search/results
path, with the proper state in this.props.history.location.state
. However: in this.props.children
, the only path in this.props.children.props
was /search
…oh! wait a minute…
And that was my "aha" moment! The error was triggered because the library couldn't find any root that matches /search
, because I forgot it in my root component. So what I did was: add /search
as a potential path: and everything was back to normal, up and running, sexier than a mug 🌈🦄 !
Hope this could help any of you facing the same issue with React Router Navigation (or any other related library) 😃
This looks interesting. Is this doable?
If you call history.replace
and the current route has a title, and the new route has a title, then two titles will show in the navbar.
This is my code
<Navigation navBarStyle={{ backgroundColor: 'purple' }} titleStyle={{ color: 'white' }}>
<Card exact path="/watch" component={SeriesOverview} />
<Card exact path="/watch/series/:seriesId" component={SeriesDetail} />
</Navigation>
It seems that if you navigate back from SeriesDetail to SeriesOverview, the Component is rerendered without the match and history object. I wanted to ask why it behaves like that?
https://github.com/LeoLeBras/react-router-navigation/blob/master/modules/DefaultRenderer.js#L54 seems to assume that routeName would be unique amongst all the scenes, but it doesn't have to be. In the event it's not unique, the wrong scene is rendered
Hello!
First of all, thanks for this great library!
Secondly, I have an issue with the NavBar. I have a scene
<Navigation>
<Card title="Home" exact path="/app" render={ownProps => <HomeContainer {...ownProps} />} /
</Navigation>
and I want to render some buttons in the NavBar. I know that I can use renderLeftButton on the Card, but I want to set them from the HomeContainer component. Is there any way to do that?
How to support collapsible Navbar ?
or Should i use Custom Navbar ?
Is it possible to add tabs (Tab component) dynamically for BottomNavigation and Tabs?
For tabs, when i push my new tab it shows only when i navigate back and forth to the screen which has tabs, but i want id like to see it appear right away. Same thing for BottomNavigation.
Thanks :)!
Hello,
This navigation package makes the most sense for me as compared to the zillions out there in react native land.
Could you publish the most latest version to NPM please? I guess the one currently live on npm is almost 6 months old. I'm unable to run the one from github directly. Thanks.
Two tabs using BottomNavigation:
<BottomNavigation
lazy={true}
tabActiveTintColor="blue">
<Tab label="Accounts" path="/accounts" component={Accounts} />
<Tab label="Profile" path="/profile" component={Profile} />
</BottomNavigation>
In the Accounts component, I have:
componentDidMount() {
console.log('Accounts mounted')
}
componentWillUnmount() {
console.log('Accounts unmounted')
}
render() {
return (
<Navigation
navBarStyle={{ backgroundColor: 'purple' }}
titleStyle={{ color: 'white' }}>
<Card
exact path='/accounts'
title='Accounts'
render={() => (
<View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
<Text>Accounts</Text>
<Link to='/test'><Text>Go To Test</Text></Link>
</View>
)}
/>
<Card
exact path='/test'
title='Test'
component={Test}
/>
</Navigation>
)
}
}
Expected Result: Test Component shouldn't be unmounted when switching back to the Accounts tab.
Is my setup incorrect?
I want to change the route which user is after a particular time of function
See Example of cod below
setTimeout(
() => {
firstTime(DeviceInfo.getUniqueID())
.catch(function () {
//where the change works
});
}, 2000
);
Add explicit docs on how to use react-router-navigation
.
Is there any documentation other than this on onRequestChangeTab
and onReset
.
What I want to do is just call this.props.history.push('/my/path')
from a tab. But it throws an error saying- Invariant violation: there should always be only one screen active, not 0
.
How do I navigate to a different route from a Tab
?
I think the first example in the README is missing tags:
<Card
exact
path="/"
render={() => <Link to="/hello"><Text>Press it</Text></Link>}
/>
import React,{Component} from 'react'
import {View,Text} from 'react-native'
import { BottomNavigation,Tab } from 'react-router-navigation'
export default class Main extends Component{
render(){
return(
<BottomNavigation
lazy={false}
tabActiveTintColor="blue">
<Tab label="Feed" path="/Feed" Component={require('./Feed')}/>
<Tab label="Profile" path="/Profile" Component={require('./Profile')}/>
</BottomNavigation>
);
}
}
Thanks for your library!
Could you recommend solution for making navigation bar transparent and translucent?
We try to make it absolute, but on Android it hide under page content
Thanks
Hello guys, is there a way to make the TabBars appear over the screen like in Snapchat? I've been experimenting with setting absolute positions but that doesn't work with the animations.
Is there any way to customise BottomNavigationBar's style properties?
It would be nice to be able to change it, the same way we do with icons and labels, without creating a whole new component. A little style
prop should do the job 👌
Hey Leo,
thanks for looking into #23 and updating the Renderer. The rendering of multiple cards is not a problem anymore. However, there is now an error inside the NavBar:
I'm using the newest release candidate:
"react-router-navigation": "^1.0.0-rc.2",
I looked into the code and I think I've found something. In the DefaultRenderer replacing
return [ ...acc.slice(0,indexOf), scene ]
with
return [...acc]
and therefore, using the last occurrence in case of finding a duplicate index fixed it for me. With the old code the newly replaced route was simply sliced of again and replaced by the old one. However, the scene
in the ownProps
was still the new one, but could not be found in the newly generated scenes
, which resulted in the exception.
Thanks for looking into that and keep up the good work,
Georg
Is any support for the iPhone X planned?
Right now the safe area layout guides don't seem to be used.
react-router-native (from react-router v4) comes with DeepLink. Is supported in react-router-navigation?
Do you plan to support Modal-Views, as react-navigation provides?
At the moment the only solution seems to be using a new Navigator with custom transition while hiding the NavBar.
Greetings
Hi,
I'm trying to share a view (for example a profile view) between different tabs.
At the moment my setup is:
<BottomNavigation>
<Tab />
<Tab />
<Tab />
</BottomNavigation>
Now I'd like to have my view Profile
accessible from all those routes. Is that possible?
Cheers
Hi.
I'm using react-route
and react-router-navigation
with redux.
I've setuped 2 links in RootContainer
RootContainer.js
...
class RootContainer extends Component {
_onPress () {
window.console.log('button pressed outside of Navigation component');
}
render () {
return (
<View style={styles.applicationView}>
<StatusBar hidden={true} />
<Button title={"Button outside of Navigation"} onPress={this._onPress.bind(this)}/>
<Navigation>
<Card exact path={'/'} title="Menu" component={MainScreen}/>
<Card path={'/barcode'} title="Barcode" component={BarcodeScreen}/>
</Navigation>
</View>
);
}
}
...
MainScreen.js
...
class MainScreen extends Component {
static propTypes = {
history: PropTypes.object
};
_onBarcodePress () {
this.props.history.push('barcode');
}
render () {
return (
<View style={styles.container}>
<Button title={"Barcode"} onPress={this._onBarcodePress.bind(this)}/>
</View>
);
}
}
...
BarcodeScreen.js
...
class BarcodeScreen extends Component {
render () {
return (
<ScrollView style={styles.container}>
<KeyboardAvoidingView behavior='position'>
<Text>BarcodeScreen</Text>
</KeyboardAvoidingView>
</ScrollView>
);
}
}
...
I've normaly walk through the screens, like:
MainScreen
-> BarcodeScreen
then click BackButton on Android (not at NavBar), it back me to MainScreen
(it's OK), than click BackButton on Android one more time, application exit to Android OS (it's OK too), then I run my application and.... Button
component on MainScreen
(inside of Navigation
component) don't pressed (it's NOT OK), as if there is no click.
But interesting, that Button
in RootContainer
that outside of Navigation
component can be pressed.
Why would this happens?
Is this project still under active development?
Is there a way of changing the header title of a card dynamically as with the setParam method in react-navigation?
I have tried with this without luck
<Navigation> <Card path="/path/:id" title={this.props.condition ? 'first' : 'second' } render={...} /> </Navigation>
I am currently playing around with this lib - which is pretty fun! Good Job!
Now I tried to use Nested Navigators.
My Goal is an Introduction-Swiper to the App. So lets say three pages, that share a step-indicator (like this one: https://github.com/24ark/react-native-step-indicator).
Regarding this (https://github.com/reactjs/react-router-tutorial/tree/master/lessons/04-nested-routes) I was about to setup a base-route like so:
App:
<NativeRouter>
<Navigation>
<Card
path="/intro"
title="Intro"
component={IntroView}
/>
</Navigation>
</NativeRouter>
and then the child-views IntroView:
<View style={styles.container}>
<View>
<Navigation
hideNavBar>
<Card path="/1" component={abc} />
<Card path="/2" component={def} />
<Card path="/3" component={ghi} />
</Navigation>
</View>
<View style={styles.progress}>
<Text>{this.props.location.pathname}</Text>
</View>
</View>
This doesn't seem to work, neither does the following alternative:
<NativeRouter>
<Navigation>
<Card
path="/intro"
title="Intro"
component={IntroView}>
<Card path="/1" component={abc} />
<Card path="/2" component={def} />
<Card path="/3" component={ghi} />
</Card>
</Navigation>
</NativeRouter>
Any hint in the right direction is highly appreciated :-)
Hey, Leo! 👋
This is awesome! Thank you for making this. 🙏
Well, I'm having issues using react-router
's <Redirect />
with this library. 😭
I see a blank screen, and it renders/redirects twice resulting in the following warning:
Warning: You tried to redirect to the same route you're currently on: "/redirect"
.
Code: 👨💻
<NativeRouter>
<Navigation>
<Card
exact
path="/"
render={() => {
console.log('Redirecting.');
return (
<Redirect to="/redirect" />
);
}}
/>
<Card
path="/redirect"
render={() => (
<Text>Redirected.</Text>
)}
/>
</Navigation>
</NativeRouter>
I've also prepared a Snack
for you: https://snack.expo.io/SkgJqwz6W.
Thanks for your time. Cheers! 😃
I've got the following setup (pseudocode):
Switch
Route1 render={() =>
Navigation1
Card1
Card2
Route2 render={() =>
Navigation2
Card3
Card4
When I navigate to Route1 is works just fine. But when I try to navigate from Route1 to Route2 it throws with this error:
Element type is invalid: expected a string (for built-in components) or
a class/function (for composite components) but got: null.
Check the render method of `SceneView`.
What happens is React does not remount the Navigation
, so constructor from CardStack
doesn't run and componentWillReceiveProps
does, but it sets an empty array to state.cards
.
Versions of libs:
Let's say that I have 2 routes in my <BotttomNavigation />
: /home
& /profile
. Inside /home
, I have a /home/article
route.
I can pass props to /home/article
thanks to location.state
. But if I go to /profile
from the /home/article
and then go back to /home/article
(by touching Home's icon in <BotttomNavigation />
), I'll end up with a red error 😢 because,/profile
didn't pass anything to react-router
in location.state
.
One of the solutions could be to re-inject the current state into location.state
when the router is doing simple actions like goForward()
or goBack()
🤔
Then, while navigating from /home/article
to /profile
the router will pass the current location.state
, and if I come back to this route, the router is then doing a simple goBack()
, and I'll get my location.state
back 😃. If I go somewhere else, the router won't pass this location.state
to the new route because it won't necessarily need it!
Hi,
great navigation library!!
Just a quick question.. Is it possible to trigger navigation from an action creator in redux?
For example:
I want to log in a user, and after a successful login redirect the user to a specific page.
For now I'm listening to a componentWillReceiveProps()
in my login component but that's very dirty...
Thanks!
David
Hi!
You should probably renamed the clean
script because it's a Yarn
command. I'd suggest something lik cache-clean
instead :) !
Hi, is there a way to implement your navigation library with Redux
and redux-saga
?
I prefer to navigate in some cases from sagas
, and want to see the state of navigation in the redux store
I'm super excited about this library. 😭
Does anyone feel like working on TypeScript type declarations with me?
We can add them to https://github.com/DefinitelyTyped/DefinitelyTyped
Hey guys,
I checked out your package and came across some problems on iOS and Android. It seems that cards are rendered multiple times by the CardStack
even though they should only be rendered once when I replace the current history.
I dispatch a replace
from react-router-redux in an action creator that reroutes to my index Card like this:
export function setStoryActive(userId, storyId) {
return (dispatch) => {
dispatch(setStoryActiveStart());
return postActiveStory(userId, storyId)
.then(json => {
dispatch(setStoryActiveSuccess(json));
dispatch(getStoryProgress(userId, storyId))
dispatch(replace('/'));
}).catch((e) => {
console.error(e);
dispatch(setStoryActiveError(e.message));
})
};
}
In general, the redirect and replace works. However, it seems that despite the replace the old card is still rendered below the new replaced one:
As can be seen that leads to the overlapped text in the middle and the rendering of the back button (which should not be present and which actually cannot be clicked, because it lays beneath).
I'm using a setup with
"react-router": "^4.1.1",
"react-router-native": "^4.1.1",
"react-router-navigation": "^1.0.0-rc.0",
"react-router-redux": "^5.0.0-alpha.6",
I would really appreciate fast help with that problem. :)
Btw, I love your package! Saw the great lightning talk from @CharlesMangwa at ReactConf and really like the way you guys handle the navigation! 👍
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.