Custom backButtonIcon for NavigatorIOS - react-native

This question is related to
https://github.com/facebook/react-native/issues/1383
Is there anyway to have a custom back button icon / title with NavigatorIOS?
backButtonIcon, backButtonTitle is not working as expected. The left arrow is always visible. New routes with custom backButtonIcon or backButtonTitle doesnt show
this.props.navigator.push({
title: 'Next',
component: Next,
backButtonIcon: require('./../img/Back.png')
})

Use LeftButtonIcon instead of backButtonIcon like this;
this.props.navigator.push({
title: '详情',
component: PageList,
leftButtonIcon: {uri: 'nav-back'},
onLeftButtonPress: () => {
ViewController.toggleTabBar(true);
this.props.navigator.pop();
},
passProps: {
data: data
}
});
The letButtonIcon comes from Native App.

You can easily achieve this using the Navigator component. Navigator is the JS implementation of a navigator. You can customize every aspect of it and you can use it in both iOS and Android. Further more, NavigatorIos is not maintained as much as Navigator. More info here: https://facebook.github.io/react-native/docs/navigator-comparison.html#content
And here:
https://facebook.github.io/react-native/docs/navigator.html#content

Related

Refresh inside function of react-navigation screen

Using react-navigation I am doing stuff inside one of screens, where I display items, and optionally delete them. When deleting, I need to update the screen, which I am having trouble with. I tried navigating to the same screen or updating useState hook variables, which should re-render the screen but dont. For now, I am refreshing it in the dumbest way: I delete the item, navigate to other screen, timeout 5ms and go back to the screen that I want to update.
function ListScreen({navigation}) {
<FlatList>
...stuff
<ListItem.Chevron onPress={ () => Alert.alert('Alert Title', 'Do you really want to delete this?',
[{ text: 'YES', onPress: () => deleteAndRefresh(id) }
/>
function deleteAndRefresh(id) {
deleteProduct(id); //database call
navigation.navigate('Home');
setTimeout(function () {
navigation.navigate('List');
}, 5);
}
}
How could I refresh the screen inside deleteAndRefresh more ... elegantly?
Did you try push ?
navigation.push('List');

Rendering a TabNavigator in Storybook

I want to use Storybook.js to mock up a page that utilizes createMaterialTopTabNavigator(). However I can't render the material Tab because the output of the function is not actually a react component. So when I directly tried <TabNavigator /> it threw an invariant violation that "navigation" was missing. The only work-around I found was using createAppContainer() around the TabNavigator. But I know that it is bad practice to use more than one navigator. Is there any way to render a react navigator element without needing the navigation container?
This is my current working code for the storybook:
const tabConfiguration = {
Old: {
screen: OldProductsScreen,
navigationOptions: {
title: "Old"
}
},
New: {
screen: NewProductsScreen,
navigationOptions: {
title: "New"
}
}
};
const TabNavigator = createMaterialTopTabNavigator(tabConfiguration);
storiesOf('Test', module)
.add('Initial', () => {
const TAB = createAppContainer(TabNavigator);
return (
<TAB / >
);
})
;
I know that it is bad practice to use more than one navigator. Is there any way to render a react navigator element without needing the navigation container?
It's bad practice to do that in an app. But since you're using Storybook where each container is in like its own independent app, this is totally fine.

React native: How to navigate nested navigator (wrapped by a component)

I read on the docs about navigating nested navigator https://reactnavigation.org/docs/en/navigation-actions.html#setparams
const navigateAction = NavigationActions.navigate({
routeName: 'Profile',
params: {},
action: NavigationActions.navigate({ routeName: 'SubProfileRoute'})
})
this.props.navigation.dispatch(navigateAction)
However, my nested navigator SubProfileRoute is wrapped by a component
module.exports = class _ extends React.Component { ... }
not
module.exports = StackNavigator({})
So how do i do it?
You'll need to assign the router of the child navigator to the component wrapping it - that way the outer navigator will pass the navigation property to the child navigator.
See explicitly rendering more than one navigator.
So, I managed to solve this problem on my side. The issue is the links shared here don't work, even though Kraylog's answer provides a good place to start the research.
I found that, in order for nested routers to work, the navigation does indeed look for a child router in the component that it renders. However, it's not enough to set the router property to a child router's for everything to work with, in my example, redux navigation.
You also need to pass the navigation prop manually to the child navigator.
The documentation that helped a bit is this custom navigator guide.
The solution ended up being a simple one:
class MyNavigator extends React.Component {
static router = NestedNavigator.router;
render() {
return <NestedNavigator navigation={this.props.navigation} />;
}
}

React Navigation: Prevent multiple instances to navigate to same screen

Let's say I have this screen:
And when the user clicks on the white tooltip, it redirects to another screen. Sometimes the app lags a little bit, and clicking on the tooltip takes like ~2s to see the screen change. The problem is, during those 2s, the user taps again on this tooltip to make it happen.
And the result I get is that there are two instances of the new screen in my StackNavigator. What I mean is that I see my new screen, but when I click on "Back" I don't return to this 'Hitchhiking Map' screen, but to another instance of that same screen.
If I clicked 5 times on the callout during those 2s, then I need to click 5 times "Back" to return to the Map screen. Any way to prevent that? To put only one instance into the StackNavigator?
I am using React Navigation, more precisely a StackNavigator. Here's my code:
The "click on tooltip" part:
<MapView.Marker
onCalloutPress={() => this.props.navigation.navigate('spotDetails', { spotId: marker.id })}
/>
My screens:
const HMapNavigator = StackNavigator({
HMap: { screen: HMapViewContainer },
spotDetails: { screen: SpotDetailsViewContainer },
});
The issue of multiple navigations has been reported and there is more detail here.
react-navigation (v1.0.0-beta.7) is in beta and still being built, so until this feature is implemented, you will have to handle the debounce manually.
options
disable the button once the navigation starts
debouncing in the onPress logic or in the action if you are using redux
lodash provides a useful debounce utility, if you are looking for one.
There are many ways how to overcome double navigations.
My solution is adding a key property in navigate object:
this.props.navigation.navigate({ key: 'AnotherScreen', routeName: 'AnotherScreen', params: { ... }})}
Save if its opening to control the navigation
constructor (props) {
super(props)
this.state = {
opening: false
}
}
Create a function to control de navigation
_open (campaign) {
if (!this.state.opening) {
this.props.navigation.navigate('Campaign', {campaign})
this.setState({ opening: true })
setTimeout(() => {
this.setState({ opening: false })
}, 1000)
}
}
Call this func from your onpress
<TouchableHighlight underlayColor='transparent' onPress={this._open.bind(this, campaign)}>
In versions 1.x of React Navigation, if you specify an identifier the navigation action will be executed only once. E.g.:
navigate({ routeName: 'someScreen', key: 'someScreen', params: { someParam: 'someValue' } })
More information: https://gist.github.com/vonovak/ef72f5efe1d36742de8968ff6a708985
In versions 2.x and 3.x this is a default functionality.
More info: https://reactnavigation.org/docs/en/navigation-key.html

Triggering an action of a different page using NavigatorIOS Buttons

I'm making an app with two Buttons in the Navigator in the Homepage. I have also used React Native Side Menu. (https://github.com/react-native-fellowship/react-native-side-menu)
From the left button of the NavigatorIOS, I want to trigger the toggle() method of the Side Menu. How am I to accomplish this?
<NavigatorIOS
style={styles.navigationContainer}
ref="nav"
initialRoute={{
title: "Home",
component: Home,
ref:'home',
rightButtonTitle: 'Items',
leftButtonTitle: 'Menu',
onLeftButtonPress: () => {
//menuActions.toggle(); HERE IS THE PROBLEM
},
onRightButtonPress: () => {
this.refs.nav.navigator.push({
title: "Items",
component: Items
});
}
}} />
The code and the elements for the Sidemenu is in the Home file. How to access this from this code, which is in the index.ios.js?
Thanks in advance.
I'm afraid that's not enough to make a conclusion. First of all, I need to see, how you compose your components. menuActions are available only for children components thru the context. Based on this code fragment I can't see how you make do it.
My suggestions:
- Check if you NavigatorIOS component is a children of your SideMenu component
- If you don't want to use NavigatorIOS as a children of a SideMenu, you may need something like a global store (you can use redux, for example) which will reflect a state of the SideMenu. Subscribing to this store from the right place (in any children of SideMenu), you'll be able to trigger menuActions from the place it'll be accessible.