react-navigation Custom Drawer not rerender - reactjs

Style styles.draweritemstxt_active and styles.draweritemstxt_inactive not set / rerender when I try to choose other drawer item.
Navigator.js
const MainDrawer = DrawerNavigator({
Event: { screen: EventScreen },
Wallet: { screen: WalletScreen},
Profile: { screen: ProfileScreen},
Contact: { screen: MemberContactScreen},
Reward: { screen: MemberRewardScreen},
},{
contentComponent: props => <DrawerScreen {...props} />
});
DrawserScreen.js
const DrawserScreen = props => {
let totalitem = props.items;
return(
<ScrollView style={{backgroundColor:'#000'}}>
<SafeAreaView forceInset={{ top: 'always', horizontal: 'never' }}>
{
totalitem.map((ritem,i)=>{
let txtstyle = null;
if(props.activeItemKey == ritem.key){
txtstyle = styles.draweritemstxt_active;
}else{
txtstyle = styles.draweritemstxt_inactive;
}
return(
<TouchableHighlight key={i} activeOpacity={0.9} onPress={()=> props.navigation.navigate(ritem.key)} style={styles.draweritems}>
<View>
<Text style={txtstyle}>{_convertRouteToTitle(ritem.routeName)}</Text>
</View>
</TouchableHighlight>
);
})
}
</SafeAreaView>
</ScrollView>
);
}
export default DrawserScreen;

Related

Unable to remove existing params in react navigation

I'm using react-navigation v4 for my expo App. For my App I'm using createDrawerNavigator and createSwitchNavigator with createAppContainer and createBrowserApp for web.
My issue is when I'm navigating to a route where I don't want params, there also it's passing me parameters. like,
http://localhost:19006/App/SkyView (first I visited route without
params)
http://localhost:19006/App/CasesList (I visited another route, from
there I'm passing params to SkyView route)
it redirect me to http://localhost:19006/App/SkyView?caseId=HYDE200627-00064&tripIndex=0
after that If I want to visit http://localhost:19006/App/SkyView it navigating to http://localhost:19006/App/SkyView?caseId=HYDE200627-00064&tripIndex=0
My DrawerNavigator code
const DrawerNavigation = createDrawerNavigator({
CasesList: {
screen: MainAuth(CasesList),
navigationOptions: {
drawerIcon: ({ tintColor }) => (<FontAwesome5 name='map-marked-alt' size={18} style={{color:tintColor}}/>)
}
},
SkyView: {
screen: MainAuth(SkyView),
navigationOptions: {
drawerIcon: ({ tintColor }) => (<FontAwesome5 name='map-marked-alt' size={18} style={{color:tintColor}}/>)
}
},
},{contentComponent: props => <CustomDrawerContentComponent {...props}/>,contentOptions: {
activeTintColor: baseColor,
itemsContainerStyle: {
marginVertical: 0,
},
iconContainerStyle: {
opacity: 1
}
}})
const CustomDrawerContentComponent = props => {
const signOutAsync = async () => {
try {
store.dispatch(logoutHandler())
props.navigation.navigate('Auth');
}
catch(exception) {
console.log(exception)
}
};
return (
<ScrollView contentContainerStyle={styles.container}>
<SafeAreaView
forceInset={{ top: 'always', horizontal: 'never' }}
>
<View style={styles.header}>
<View style={styles.avatar}>
<FontAwesome5 name="user-alt" size={24} style={{color:white}}/>
</View>
<View style={styles.userInfo}>
<Text style={{}}>Abdulla Zulqarnain</Text>
</View>
</View>
<DrawerItems {...props} />
</SafeAreaView>
<TouchableOpacity onPress={()=>signOutAsync()}>
<View style={styles.item}>
<View style={styles.iconContainer}>
<FontAwesome5 name='sign-out-alt' size={18} style={{color:red_dark}}/>
</View>
<Text style={styles.label}>Logout</Text>
</View>
</TouchableOpacity>
</ScrollView>
);
}
other Routing code
const routes = createSwitchNavigator(
{
AuthLoading: {
screen: AuthLoadingScreen,
navigationOptions: {
header: null,
}
},
App: {
screen: DrawerNavigation,//MainAuth(CasesList),
navigationOptions: {
header: null,
}
},
Auth:{
screen: Login,
navigationOptions: {
tabBarVisible: false,
header: null,
},
},
HospitalList: {
screen: HospitalList,
navigationOptions: {
header: null,
}
},
},
{
initialRouteName: 'AuthLoading',
defaultNavigationOptions: {
}
}
);
const container = isWeb ? createBrowserApp(routes): createAppContainer(routes);
I'm stuck since 2 days can anyone help me to sortout this issue.

Reducer State Variables returning Undefined State in Tab Navigator Screen

I have three bottom navigation tabs (Captain, Weapon, Engineer). The Captain Tabs displays Current HP & Enemy HP. The Weapon tab displays Enemy HP and 3 buttons. The Engineer Tab displays Current HP and 3 buttons.
I'm trying to display all these various HP values through the use of React Redux and reducers to display all these state variables. However when the various screens get rendered. They all return NaN for the state variables.
How do we go about returning the default state variables as opposed to returning NaN/undefined for the different tabs?
Here is my main screen that holds all these tab navigation screens: Game.js
import React, { Component } from 'react';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
import * as Progress from 'react-native-progress';
import { createStore } from 'redux'
import { Provider, connect } from 'react-redux'
import reducer from '../../src/store/reducer'
import {
SafeAreaView,
StyleSheet,
ScrollView,
View,
Text,
StatusBar,
Button
} from 'react-native';
import { createAppContainer } from 'react-navigation';
import { createMaterialBottomTabNavigator } from 'react-navigation-material-bottom-tabs';
const store = createStore(reducer);
class CaptainScreen extends React.Component {
render() {
console.log(this.props.hpBar);
console.log(this.props.enemyBar)
return (
<View style={styles.container}>
<Text style={styles.title}>Captain Screen</Text>
<View style={styles.container2} >
<Progress.Bar progress={this.props.hpBar} width={200} animated={true} borderColor={'black'} />
<Text style={styles.text}>Your HP: {this.props.hpBar * 100}%</Text>
<Progress.Bar progress={this.props.enemyBar} width={200} color={'red'} animated={true} borderColor={'black'} />
<Text style={styles.text}>Enemy HP: {this.props.enemyBar * 100}%</Text>
</View>
</View>
)
}
}
class WeaponsScreen extends React.Component {
render() {
const { navigate } = this.props.navigation;
return (
<View style={styles.container}>
<Text style={styles.title}>Weapons Screen</Text>
<View style={styles.container2} >
<Progress.Bar progress={this.props.enemyBar} width={200} color={'red'} animated={true} borderColor={'black'} />
<Text style={styles.text}>Enemy HP: {(this.props.enemyBar * 100).toFixed(0)}%</Text>
<Button title="Weapon 1" onPress={this.props.onWeapon}> </Button>
<Button title="Weapon 2" onPress={() => this.weaponTwo()}> </Button>
<Button title="Weapon 3" onPress={() => this.weaponThree()}> </Button>
</View>
</View>
)
}
}
class EngineersScreen extends React.Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.title}>Engineer Screen</Text>
<View style={styles.container2} >
<Progress.Bar progress={this.props.hpBar} width={200} animated={true} borderColor={'black'} />
<Text style={styles.text}>Your HP: {(this.props.hpBar * 100).toFixed(0)}%</Text>
<Button title="Quick Fix" onPress={() => this.quickFix()}> </Button>
<Button title="Medium Fix" onPress={() => this.mediumFix()}> </Button>
<Button title="Indepth Fix" onPress={() => this.indepthFix()}> </Button>
</View>
</View>
)
}
}
const TabNavigator = createMaterialBottomTabNavigator(
{
Captain: {
screen: CaptainScreen,
navigationOptions: {
tabBarIcon: ({ tintColor }) => (
<View>
<Icon name="ship-wheel" style={[{ color: tintColor }]} size={25} />
</View>
),
}
},
Weapons: {
screen: WeaponsScreen,
navigationOptions: {
tabBarIcon: ({ tintColor }) => (
<View>
<Icon name="pistol" style={[{ color: tintColor }]} size={25} />
</View>
),
activeColor: '#ffffff',
inactiveColor: '#a3c2fa',
barStyle: { backgroundColor: '#2163f6' },
}
},
Engineer: {
screen: EngineersScreen,
navigationOptions: {
tabBarIcon: ({ tintColor }) => (
<View>
<Icon name="hammer" style={[{ color: tintColor }]} size={25} />
</View>
),
activeColor: '#ffffff',
inactiveColor: '#92c5c2',
barStyle: { backgroundColor: '#2c6d6a' },
}
},
},
{
initialRouteName: 'Captain',
activeColor: '#ffffff',
inactiveColor: '#bda1f7',
barStyle: { backgroundColor: '#6948f4' },
}
);
const mapStateToProps = (state) => {
console.log(state);
return {
hpBar: state.hpBar,
enemyBar: state.enemyBar
}
}
const mapDispatchToProps = (dispatch) => {
return {
onEngineer: () => dispatch({ type: 'HP_UP', payload: 0.1 }),
onWeapon: () => dispatch({ type: 'HP_DOWN', payload: 0.1 })
}
}
const ConnectedApp = connect(mapStateToProps, mapDispatchToProps)(TabNavigator);
const Game = createAppContainer(ConnectedApp);
export default Root = () => {
return (<Provider store={store}><Game /></Provider>)
}
Here is my reducer file: Reducer.js
const initialState = {
hpBar: 1.0,
enemyBar: 1.0,
};
const reducer = (state = initialState, action) => {
const newState = { ...state };
switch (action.type) {
case 'HP_UP':
return {
...state,
hpBar: state.hpBar + action.payload
}
break;
case 'HP_DOWN':
return {
...state,
enemyBar: state.enemyBar - action.payload,
}
break;
}
return newState;
};
export default reducer;

How do i navigate to a new screen from FlatList?

I would like to navigate to a screen called GridVid when clicking the items in my FlatList. I can't figure out how to do this as the
onPress={() => this.props.navigation.navigate('GridVid')}
only will work being called in App.js as thats where the StackNavigator is defined, not the ListItem class (which is in a separate file called ListItem.js)
//App.js
class SettingsClass extends Component {
constructor(props) {
super(props)
this.state = {
columns: 3, //Columns for Grid
};
}
render() {
const {columns} = this.state
return (
<View style={styles.grid}>
<FlatList
numColumns={columns}
data={[
{uri:'https://randomuser.me/api/portraits/thumb/women/12.jpg'},
{uri:'https://randomuser.me/api/portraits/thumb/women/13.jpg'},
{uri:'https://randomuser.me/api/portraits/thumb/women/14.jpg'},
]}
renderItem={({item}) => {
return (<ListItem itemWidth={(ITEM_WIDTH-(10*columns))/columns}
image={item}
/>
)
}}
keyExtractor={
(index) => { return index }
}
/>
</View>
);
}
}
//Settings Class swipes to GridVid
const SettingsStack = createStackNavigator({
SettingsScreen: {
screen: SettingsClass
},
GridVid: {
screen: GridVidClass
},
});
//ListItem.js
export default class ListItem extends Component {
state = {
animatepress: new Animated.Value(1)
}
animateIn() {
Animated.timing(this.state.animatepress, {
toValue: 0.90,
duration: 200
}).start()
}
animateOut() {
Animated.timing(this.state.animatepress, {
toValue: 1,
duration: 200
}).start()
}
render() {
const {itemWidth} = this.props
return (
<TouchableWithoutFeedback
onPressIn={() => this.animateIn()}
onPressOut={() => this.animateOut()}
onPress={() => this.props.navigation.navigate('GridVid')} //WONT WORK HERE in this file!!!!
>
<Animated.View style={{
margin:5,
transform: [{scale: this.state.animatepress}] }}>
<Image style={{width:itemWidth, height: 100}} source={this.props.image}></Image>
</Animated.View>
</TouchableWithoutFeedback>
);
}
}
//GridVid.js
export default class GridVidClass extends Component {
render() {
return (
<View style={styles.container}>
<Text>On GridVid </Text>
</View>
);
}
}
Is there any way to call onPress={() => this.props.navigation.navigate('GridVid') within the FlatList (or anywhere in App.js) as opposed to ListItem (where it wont work at the moment)? In ListItem however, at least i'm clicking the image that i want and have some reference to what i'm clicking.
What you need to do is pass a onPress prop to your ListItem that will make the navigation happen.
//App.js
class SettingsClass extends Component {
constructor(props) {
super(props)
this.state = {
columns: 3, //Columns for Grid
};
}
render() {
const {columns} = this.state
return (
<View style={styles.grid}>
<FlatList
numColumns={columns}
data={[
{uri:'https://randomuser.me/api/portraits/thumb/women/12.jpg'},
{uri:'https://randomuser.me/api/portraits/thumb/women/13.jpg'},
{uri:'https://randomuser.me/api/portraits/thumb/women/14.jpg'},
]}
renderItem={({item}) => {
return (<ListItem itemWidth={(ITEM_WIDTH-(10*columns))/columns}
image={item}
onPress={() => this.props.navigation.navigate('GridVid') // passing the onPress prop
/>
)
}}
keyExtractor={
(index) => { return index }
}
/>
</View>
);
}
}
//Settings Class swipes to GridVid
const SettingsStack = createStackNavigator({
SettingsScreen: {
screen: SettingsClass
},
GridVid: {
screen: GridVidClass
},
});
//ListItem.js
export default class ListItem extends Component {
state = {
animatepress: new Animated.Value(1)
}
animateIn() {
Animated.timing(this.state.animatepress, {
toValue: 0.90,
duration: 200
}).start()
}
animateOut() {
Animated.timing(this.state.animatepress, {
toValue: 1,
duration: 200
}).start()
}
render() {
const {itemWidth} = this.props
return (
<TouchableWithoutFeedback
onPressIn={() => this.animateIn()}
onPressOut={() => this.animateOut()}
onPress={this.props.onPress} // using onPress prop to navigate
>
<Animated.View style={{
margin:5,
transform: [{scale: this.state.animatepress}] }}>
<Image style={{width:itemWidth, height: 100}} source={this.props.image}></Image>
</Animated.View>
</TouchableWithoutFeedback>
);
}
}
ListItem is not in StackNavigator so it doesn't know what navigation is
You can go with like Vencovsky's answer or pass navigation prop from ListItem's parent component
<ListItem
itemWidth={(ITEM_WIDTH-(10*columns))/columns}
image={item}
navigation={this.props.navigation}
/>

React native how to animate view opening up->down

Consider the following component where the user selects an option from a list:
import React, { Component } from "react";
import PropTypes from "prop-types";
import {
View,
Text,
StyleSheet,
Platform,
FlatList,
TouchableNativeFeedback,
TouchableOpacity,
PLatform
} from "react-native";
import Icon from "react-native-vector-icons/Ionicons";
import { colors, metrics } from "../../themes";
const Touchable =
Platform.OS === "android" ? TouchableNativeFeedback : TouchableOpacity;
class MenuSelector extends Component<{
onSelect: () => any,
config: object,
selected: string
}> {
state = {
listOpened: false
};
handlePress = id => {
this.props.onPress(id);
};
handleSelect = id => {
if (this.props.onSelect) this.props.onSelect(id);
this.setState({
listOpened: false
});
};
handleMenu = () => {
this.setState({
listOpened: !this.state.listOpened
});
};
render = () => {
let title = "";
if (this.props.config) {
title = this.props.config[0].title;
if (this.props.selected) {
let found = this.props.config.find(item => {
return item.id === this.props.selected;
});
if (found) title = found.title;
}
}
let top = (
<View style={styles.header}>
<Text style={styles.text}>{title}</Text>
<Touchable>
<Text style={styles.text}>
<Icon
name={"ios-menu"}
size={20}
onPress={this.handleMenu}
/>
</Text>
</Touchable>
</View>
);
let list = null;
if (this.state.listOpened === true) {
list = (
<FlatList
data={this.props.config}
renderItem={({ item }) => (
<Touchable onPress={this.handleSelect}>
<Text style={[styles.text, styles.listItem]}>{item.title}</Text>
</Touchable>
)}
/>
);
}
return (
<View style={styles.container}>
{top}
{list}
</View>
);
};
}
export default MenuSelector;
const styles = StyleSheet.create({
container: {
flex: -1,
flexDirection: "column"
},
header: {
flex: -1,
flexDirection: "row",
justifyContent: "space-between",
padding: 10,
backgroundColor: "blue"
},
text: {
fontSize: 16,
color: "white",
textAlign: "center",
fontWeight: "bold"
},
listItem: {
padding: 10,
backgroundColor: "blue"
}
});
The component is used in the following context:
let config = [
{
title="Option 1",
id="option1"
},
{
title="Option 2",
id="option2"
},
{
title="Option 3",
id="option3"
},
{
title="Option 4",
id="option4"
},
];
return (
<View style={styles.container}>
<MenuSelector
config={config.options}
selected={this.state.mode}
onPress={this.handleButtonListPress}
/>
<FlatList
data={this.props.data}
keyExtractor={(item, index) => index.toString()}
renderItem={({ item }) => (
<Text style={styles.text}>{item.name}</Text>
)}
/>
</View>
);
As it is, the <MenuSelector> component appears "at once" on screen. I need to add an sliding effect to <MenuSelector>, "pushing down" the data FlatList when appearing on screen...
On closing, same behaviour, but animating from down to up.
How can I add such animation behaviour to my MenuSelector component ?

Navigate to different screen from a button in a header

I am using the new React-navigation from react-native. I have the navigation as follows:
StackNavigator:
TabNavigator // HomeNavigation
TabNavigator // NotificationNavigation
Full code:
const MainNavigation = StackNavigator({
Home: {
screen: HomeNavigation,
},
Notification: {
screen: NotificationNavigation,
}
});
const HomeNavigation = TabNavigator({
AllPost: {
screen: All,
},
ArticlePost: {
screen: Article,
},
BusinessPost: {
screen: Job,
},
});
HomeNavigation.navigationOptions = {
title: 'Home',
header: {
right: <SearchNotification/>
},
};
class SearchNotification extends React.Component {
goToNotification = () => {
this.props.navigate('Notification');
};
render() {
return (
<View style={styles.container}>
<TouchableOpacity>
<Icon name="md-search" style={styles.Icon}/>
</TouchableOpacity>
<TouchableOpacity style={styles.notificationWrapper} onPress={this.goToNotification}>
<Icon name="md-notifications" style={styles.Icon}/>
<Text style={styles.number}>3</Text>
</TouchableOpacity>
</View>
)
}
}
const NotificationNavigation = TabNavigator({
Comment: {
screen: NotificationComment,
},
Follow: {
screen: NotificationFollow,
}
});
HomeNavigation has a header, and the header has a right component of SearchNotification. SearchNotification has an icon which on press I would like to go to the NotificatoinNavigation.
However, if I make changes to the header of HomeNavigation to this way, the SearchNotification is not displayed in the header.
HomeNavigation.navigationOptions = {
title: 'Home',
header: {
tintColor: 'white',
style: {
backgroundColor: '#2ec76e',
},
right: ({navigate}) => <SearchNotification navigate={navigate}/>
},
};
How can I navigate to different screen from a button in a header?
So the problem was (I think), inside the navigationOptions instead of using navigations I had to use navigate, and pass it as a props to the child (i.e. the SearchNotification).
So the final code looks like this:
HomeNavigation.navigationOptions = {
title: 'Home',
header: ({navigate}) => ({
right: (
<SearchNotification navigate={navigate}/>
),
}),
};
And within the SearchNotification component:
export default class SearchNotification extends React.Component {
goToNotification = () => {
this.props.navigate('Notification');
};
render() {
return (
<View style={styles.container}>
<TouchableOpacity>
<Icon name="md-search" style={styles.Icon}/>
</TouchableOpacity>
<TouchableOpacity style={styles.notificationWrapper}
onPress={() => this.props.navigate('Notification')}>
<Icon name="md-notifications" style={styles.Icon}/>
<Text style={styles.number}>3</Text>
</TouchableOpacity>
</View>
)
}
}
Code that worked for me:
import Header from '../Containers/Header'
.........................................
navigationOptions: ({ navigation }) => ({
title: 'Find User',
headerRight: <Header navigation={navigation} />,
headerStyle: styles.header
})
And to move to other screen:
this.props.navigation.navigate('UserDetail', {});

Resources