How to relate react native ToolbarAndroid with Navigator - react-native

I would like to know a way to relate ToolbarAndroid with the Navigator component. My intention is always to show the route.title in a ToolbarAndroid child, such as a Text component. This way, if a use the BackAndroid component, my title is always up to date! I don't want to use Navigator.NavigationBar because I would miss the overflow menu built in on the ToolbarAndroid.
Appreciate any help.
Here is my code:
//... some code before
render() {
return(
<DrawerLayoutAndroid
drawerWidth={300}
ref={(drawerElement) => { this.DRAWER = drawerElement; }}
drawerPosition={DrawerLayoutAndroid.positions.left}
onDrawerOpen={this.setDrawerState}
onDrawerClose={this.setDrawerState}
renderNavigationView={() => <DrawerMenu navigate={this.navigateTo} />}
>
<Icon.ToolbarAndroid
titleColor='#fff'
navIconName='md-menu'
onIconClicked={this.toggleDrawer}
actions={toolbarActions}
onActionSelected={this._onActionSelected}
style={styles.appBar}
overflowIconName="md-more"
>
<View>
<TouchableOpacity
onPress={this.navigateTo.bind(this, 0)}
style={styles.appBarLogo}
>
<Icon name="md-boat" size={30} color="#fff" />
<Text
style={styles.appBarTitle}
numberOfLines={1}
>
{this.state.title}
</Text>
</TouchableOpacity>
</View>
</Icon.ToolbarAndroid>
<Navigator
initialRoute={routes[0]}
renderScene={(route, navigator) => {
switch (route.index) {
case 0:
return <Home />
case 1:
return <Lindau />;
case 2:
return <About />;
case 3:
return <Credits />;
default:
return <Home />;
}
}}
configureScene={(route, routeStack) =>
Navigator.SceneConfigs.FloatFromRight
}
ref={(nav) => { this._navigator = nav; }}
/>
</DrawerLayoutAndroid>
);
}

So, please, help me if anyone has a better solution for this. After several attempts, I figured out one possible solution.
I created a state for my component called 'routes', then, I've set up my Toolbar title with this state. Basically, this state is a stack of my routes. When I change my scene, I push this route in my state, when I back from BackAndroid component, I pop out the route from the state, and everything works fine.
Here the code fixed:
class App extends Component {
constructor(props) {
super(props);
this.state = {
routes: [0], // Here the state to fix the problem...
drawerClosed: true,
}
this.toggleDrawer = this.toggleDrawer.bind(this);
this._onActionSelected = this._onActionSelected.bind(this);
this.navigateTo = this.navigateTo.bind(this);
this.setDrawerState = this.setDrawerState.bind(this);
this.handlesBackButton = this.handlesBackButton.bind(this);
}
navigateTo(idx) {
this.setState({
routes: [ ...this.state.routes, idx]
});
this.DRAWER.closeDrawer();
if (idx === 0) {
this._navigator.resetTo(routes[0]);
this.setState({
routes: [0]
});
} else {
this._navigator.push(routes[idx]);
}
}
handlesBackButton() {
if (this._navigator && this._navigator.getCurrentRoutes().length > 1) {
try {
this._navigator.jumpBack();
const _routes = this.state.routes.slice();
_routes.pop();
this.setState({
routes: _routes
});
} catch(e) {}
return true;
}
return false;
}
render() {
return(
<DrawerLayoutAndroid
drawerWidth={300}
ref={(drawerElement) => { this.DRAWER = drawerElement; }}
drawerPosition={DrawerLayoutAndroid.positions.left}
onDrawerOpen={this.setDrawerState}
onDrawerClose={this.setDrawerState}
renderNavigationView={() => <DrawerMenu navigate={this.navigateTo} />}
>
<Icon.ToolbarAndroid
titleColor='#fff'
navIconName='md-menu'
onIconClicked={this.toggleDrawer}
actions={toolbarActions}
onActionSelected={this._onActionSelected}
style={styles.appBar}
overflowIconName="md-more"
>
<View style={styles.appBarLogo}> // I have to fix this component view...
<TouchableOpacity
onPress={this.navigateTo.bind(this, 0)}
>
<Icon name="md-boat" size={30} color="#fff" />
</TouchableOpacity>
<Text
style={styles.appBarTitle}
numberOfLines={1}
>
{routes[this.state.routes[this.state.routes.length - 1]].title}
</Text>
</View>
</Icon.ToolbarAndroid>
<Navigator
initialRoute={routes[0]}
renderScene={(route, navigator) => {
switch (route.index) {
case 0:
return <Home />;
case 1:
return <Lindau />;
case 2:
return <About />;
case 3:
return <Credits />;
default:
return <Home />;
}
}}
configureScene={(route, routeStack) =>
Navigator.SceneConfigs.FloatFromRight
}
ref={(nav) => { this._navigator = nav; }}
/>
</DrawerLayoutAndroid>
);
}
}

Related

React Native Cannot update during an existing state transition (such as within `render`). Render methods should be a pure function of props and state

Im learning react native, and i try to use state, now im facing an issue "Cannot update during an existing state transition (such as within render). Render methods should be a pure function of props and state."
Here my code
class Quantity extends React.Component {
constructor(props) {
super(props);
this.state = {
qty:1
};
this.setQty = this.setQty.bind(this);
}
setQty = (e) =>{
this.setState({
qty:e,
});
}
componentDidMount() {
this.props.onRef(this)
this.state.qty = 1
}
componentWillUnmount() {
this.props.onRef(undefined)
}
getCheckoutQty() {
return this.state.qty.toString();
}
minusQty = () => {
let newQty = this.state.qty -1;
this.setQty(newQty)
}
plusQty = () => {
let newQty = this.state.qty +1;
this.setQty(newQty);
}
render() {
const {qty}=this.state
return (
<View style={styles.row}>
<TouchableOpacity style={styles.icon}
disabled={(this.state.qty==1)?true:false}
// onPress={() => this.minusQty()}
>
<Icon name="minus" color="#000" style={(this.state.qty==1)?{opacity:0.2}:{opacity:1}}/>
</TouchableOpacity>
<Input
style={styles.qtyBox}
keyboardType="numeric"
returnKeyType="done"
value={qty.toString()}
onChangeText={(e)=>this.setQty(this)}
/>
<TouchableOpacity style={styles.icon}
// onPress={() => this.plusQty()}
>
<Icon name="plus" color="#000" />
</TouchableOpacity>
</View>
);
}
}
any way to fix it?
Thank for the support

Query is not being executed on time when Tab.Screen component has been called

I have a project where I am using react-navigation and I am implementing a bottom tab like this:
render() {
return (
<NavigationContainer>
<Tab.Navigator>
<Tab.Screen name="Home" component={this.HomeScreen} />
<Tab.Screen name="Settings" component={this.SettingsScreen} />
</Tab.Navigator>
</NavigationContainer>
);
}
..which is calling this.HomeScreen in one of the screens and then this.SettingsScreen in the other.
Here I will post the code of the first one:
HomeScreen({ navigation }) {
const restaurants_discounts = this.restaurants_discounts();
return (
<SafeAreaView style={styles.safeArea}>
<View style={styles.container}>
<ScrollView
style={styles.scrollview}
scrollEventThrottle={200}
directionalLockEnabled={true}>
{restaurants_discounts}
</ScrollView>
</View>
</SafeAreaView >
);
}
When the function below is called it has no data to render because this.state.discounts is empty since getDiscounts() is called later :
restaurants_discounts() {
return (
<View style={styles.exampleContainer}>
<Carousel
ref={c => this._slider1Ref = c}
data={this.state.discounts}
renderItem={this._renderDiscounts.bind(this)}
...
>
</Carousel>
</View>
);
}
getDiscounts() { //this is being called after `restaurants_discounts()` has been called
var ref = firestore().collection('discounts')
ref.onSnapshot((querySnapshot => {
var discounts = querySnapshot.docs.map(doc => { return { ...doc.data(), discount_id: doc.id } });
this.setState({
discounts: discounts
});
}));
}
}
getDiscounts() gets called in componentDidMount():
componentDidMount() {
this.getDiscounts();
}
you only return the component when this.state.discount is defined. For example:
restaurants_discounts() {
if (this.state.discounts === undefined || this.state.discounts === null)
return (<View><Text>Loading...</Text></View>);
return (
<View style={styles.exampleContainer}>
<Carousel
ref={c => this._slider1Ref = c}
data={this.state.discounts}
renderItem={this._renderDiscounts.bind(this)}
...
>
</Carousel>
</View>
);
}

How can I change the scene(Navigator) by click DrawerLayoutAndroid

guys.I need a help.
I want use DrawerLayoutAndroid and Navigator as my App navigator.
And I have a problem here.
I code like this,and it doesn't work.
<TouchableHighlight>
<Text style={styles.menu} onPress={() => this.refs['myNavigator'].navigator.push({id:'List',name:'List Page'})}>Menu Item1</Text>
</TouchableHighlight>
How can I change the scene(Navigator) by click DrawerLayoutAndroid.
Hope somebody help...
Here's the main code.
renderScene:
renderScene(route, navigator) {
var routeId = route.id;
if (routeId === 'SplashPage') {
return (
<SplashPage
navigator={navigator} />
);
}
if (routeId === 'MainPage') {
return (
<MainPage openDrawer={this.openDrawer.bind(this)}
navigator={navigator} {...route.passProps}/>
);
}
if (routeId === 'List') {
return (
<ListComponent
navigator={navigator} {...route.passProps} />
);
}
if (routeId === 'Detail') {
return (
<DetailComponent
navigator={navigator} {...route.passProps} />
);
}
if (routeId === 'Share') {
return (
<ShareComponent
navigator={navigator} {...route.passProps} />
);
}
}
render part:
var navigationView = (
<View style={{flex: 1, backgroundColor: '#161616'}}>
<Text style={styles.menuTitle}>Nav Title</Text>
<TouchableHighlight >
<Text style={styles.menu}>Home</Text>
</TouchableHighlight>
<TouchableHighlight>
<Text style={styles.menu} onPress={() => this.refs['myNavigator'].props.navigator.push({id:'List',name:'List Page'})}>Menu Item1</Text>
</TouchableHighlight>
<TouchableHighlight>
<Text style={styles.menu}>Menu Item2</Text>
</TouchableHighlight>
</View>
);
return (
<DrawerLayoutAndroid
drawerWidth={260}
ref={'DRAWER'}
drawerPosition={DrawerLayoutAndroid.positions.left}
renderNavigationView={() => navigationView}>
<Navigator
ref={'myNavigator'}
initialRoute={{id: 'SplashPage', name: 'SplashPage'}}
renderScene={this.renderScene.bind(this)}
navigator={this.props.navigator}
configureScene={(route) => {
if (route.sceneConfig) {
return route.sceneConfig;
}
return Navigator.SceneConfigs.FloatFromRight;
}}
/>
</DrawerLayoutAndroid>
)
I got it working when coded the other way around:
Render
render() {
return (
<Navigator
ref="navigator"
initialRoute={{name: "creategame", id: "creategame"}}
renderScene={this._renderScene.bind(this)}
configureScene={() => ({...FadeAndroid})}
/>
)
}
RenderScene
_renderScene(route, navigator) {
// Put your logic here selecting a component/scene based on route.id
let contentView = ...
return (
<DrawerLayoutAndroid
drawerPosition={DrawerLayoutAndroid.positions.Left}
renderNavigationView={() => <MenuView route={routeId} navigator={navigator} />}>
{contentView}
</DrawerLayoutAndroid>
)
}
Then finally call navigator.push (which is passed as a prop to my MenuView component; see example below) and you're done.
MenuView
class MenuView extends Component {
constructor() {
super();
var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
this.state = {
dataSource: ds.cloneWithRows([])
};
}
componentDidMount() {
var menuItems = [
{title: 'xxx', id: 'x'},
{title: 'yyy', id: 'y'},
... and so on
]
this.setState({
dataSource: this.state.dataSource.cloneWithRows(menuItems)
});
}
_renderMenuRow(rowData) {
return (
<TouchableHighlight onPress={this._onPress.bind(this, rowData.id)}>
<Text style={styles.menuRowText}> {rowData.title} </Text>
</TouchableHighlight>
);
}
_onPress(id) {
this.props.navigator.push({
id: id,
});
}
render() {
return (
<ListView
dataSource={this.state.dataSource}
renderRow={this._renderMenuRow.bind(this)}
);
};
}

React Native - How to re-render Navigator component on icon press

How would I re-render/ change the colour of a Navigator component icon when it is pressed. I have TouchableHighlight on it but I need the state to stay permanently. For example someone presses a 'favourite' heart icon, and it turns from grey to red. I've been trying to figure out a solution for some time now.
This is the section of my code where the change should happen. I need my if statement and Navigator icon to re-render based on the true/false value which changes when the TouchableHighlight onPress triggers.
var NavigationBarRouteMapper = {
RightButton: function(route, navigator, index, navState) {
// * The button displayed in the top right of the navigator
switch(route.id) {
case('businessProfile'):
if (route.isFavourited) {
return (
<View style={[ styles.multipleIcons ]}>
<TouchableOpacity
onPress={() => {
var favouriteBusiness = new FavouriteBusiness();
favouriteBusiness.updateBusinessAsFavourite(route.business.id)
}}
style={[ styles.navBarButton, styles.iconRightPaddingLarge ]}
>
<IconFA
name='heart'
size={ 25 }
color='#de6262'
style={ styles.icon }
/>
</TouchableOpacity>
</View>
);
} else {
return (
<View style={[ styles.multipleIcons ]}>
<TouchableOpacity
onPress={() => {
var favouriteBusiness = new FavouriteBusiness();
favouriteBusiness.updateBusinessAsFavourite(route.business.id)
}}
style={[ styles.navBarButton, styles.iconRightPaddingLarge ]}
>
<IconFA
name='heart'
size={ 25 }
color='#ddd'
style={ styles.icon }
/>
</TouchableOpacity>
</View>
);
}
default:
return null;
}
},
};
<Navigator
ref='navigator'
sceneStyle={ [styles.container, styles.inner] }
initialRoute={{
id: this.props.scene,
title:this.props.title
}}
renderScene={ this.renderScene }
configureScene={(route) => {
if (route.sceneConfig) {
return route.sceneConfig;
}
return Navigator.SceneConfigs.FloatFromRight;
}}
navigationBar={
<Navigator.NavigationBar
routeMapper={ NavigationBarRouteMapper }
style={ styles.navigationBar }
/>
}
/>
if you still did not get the solution perhaps these could help.
you can define some Properties in construktor:
constructor(props) {
super(props);
this.state = {
color: 'lightgrey',
};
}
You can define the Icon in the RooteMapper of the Navigaton bar:
return (<Icon
name="star"
style={[styles.rightHadderButton, {color: this.state.color}]}
onPress={RightNavigatorButton.favoriteStar.bind(this)}/>);
and then change the collor in the onpress defined Function:
exports.favoriteStar = function(event) {
if (this.state.color === 'lightgrey') {
this.setState({ color: '#990000' });
AlertIOS.alert( "favoriteStar","Favorite");
} else {
this.setState({ color: 'lightgrey' });
AlertIOS.alert( "favoriteStar","notFavorite");
}
}
Hope these works for you too and it helps you.

how to show navigation bar using navigator component in react-native

Hi every one I am trying to use navigator component in place of navigatorIOS, but what the problem navigator is not showing in view, below is my code for navigator and navigatorIOS
NavigatorIOS:
<NavigatorIOS
style={styles.navigator}
barTintColor='#37475e'
titleTextColor='white'
initialRoute={{
title:' Words',
component:Main
}}/>
using navigatorIOS I can view the navbar but using using navigator Component I am facing problem I want to use navigator component instead of navigatorIOS
Navigator Component:
<Navigator
style={styles.navigator}
TintColor='#37475e'
titleTextColor='white'
initialRoute={{
title:'Words',
component:Main
}}
renderScene={(route, navigator) =>{
return <route.component navigator={navigator} {...route.passProps} />;
}}/>
Can any one give me suggestions for how to solve this any help much appreciated
Yes, you need to create a <Navigator.NavigationBar />, and pass it in as a prop to the Navigator:
class App extends React.Component {
render() {
return (
<Navigator
style={{flex:1}}
initialRoute={{name: 'Main', component: Main, index: 0}}
renderScene={(route, navigator) => {
if (route.component) {
return React.createElement(route.component, { ...this.props, ...route.passProps, navigator, route } );
}
}}
navigationBar={ <Navigator.NavigationBar routeMapper={NavigationBarRouteMapper} /> }
/>
)
}
}
You then need to create a routeMapper object, which you pass in as a prop to the Navigator.NavigationBar:
var NavigationBarRouteMapper = {
LeftButton(route, navigator, index, navState) {
if(index > 0) {
return (
<TouchableHighlight style={{marginTop: 10}} onPress={() => {
if (index > 0) {
navigator.pop();
}
}}>
<Text>Back</Text>
</TouchableHighlight>
)} else {
return null}
},
RightButton(route, navigator, index, navState) {
return null;
},
Title(route, navigator, index, navState) {
return <Text>Hello From My App!</Text>
}
};
There is a great example in the UI Explorer in their GitHub, check it out here.
App.js
<Navigator
ref={(ref) => this._navigator = ref}
configureScene={(route) => Navigator.SceneConfigs.FloatFromLeft}
initialRoute={{
id: 'Main',
title: 'Words'
}}
renderScene={(route, navigator) => this._renderScene(route, navigator)}
navigationBar={
<Navigator.NavigationBar
style={styles.navBar}
routeMapper={NavigationBarRouteMapper} />
}
/>
This code for left, right and title on navigationBar in react-native
const NavigationBarRouteMapper = {
LeftButton(route, navigator, index, navState) {
switch (route.id) {
case 'Page1':
case 'Page2':
case 'Page3':
return (
<TouchableOpacity
style={styles.navBarLeftButton}
onPress={() => {_emitter.emit('openMenu')}}>
<Icon name='menu' size={25} color={'white'} />
</TouchableOpacity>
)
default:
return null
}
},
RightButton(route, navigator, index, navState) {
switch (route.id) {
case 'Page1':
return (
<TouchableOpacity
style={styles.navBarRightButton} onPress={() => {route.onPress()}}>
<Icon name={'map'} size={25} color={'white'} />
</TouchableOpacity>
)
case 'Page2':
return (
<TouchableOpacity
style={styles.navBarRightButton} onPress={() => {route.onPress()}}>
<Icon name={'map'} size={25} color={'white'} />
</TouchableOpacity>
)
case 'Page3':
return (
<TouchableOpacity
style={styles.navBarRightButton} onPress={() => {route.onPress()}}>
<Icon name={'tab'} size={25} color={'white'} />
</TouchableOpacity>
)
default:
return null
}
},
Title(route, navigator, index, navState) {
return (
<Text style={[styles.navBarText, styles.navBarTitleText]}>
{route.title}
</Text>
)
}
}
route.onPress(): method to call right button click.
route.title: set title of page.
For reference, use following link: Navigator