navigate.dispatch(DrawerActions.closeDrawer()) not working in React Native - react-native

On click of a cross button the drawer should be closed, that is the
thing I am trying. I have passed down the props inside component but
giving error that navigate.dispatch(DrawerActions.closeDrawer()) is
undefined.
I am providing My code
SideMenu.js which the layout of drawer menu. From here I am passing
props to drawerheader.
import React, {Component} from 'react';
import { View, StyleSheet} from 'react-native';
import DrawerHeader from './DrawerHeader';
import DrawerMenu from './DrawerMenu';
import { StackNavigator } from 'react-navigation';
class SideMenuLayout extends Component {
state = {
menuNames:[{
id:'0',
name:'My Profile',
link:''
},{
id:'1',
name:'Place Order',
link:''
},{
id:'2',
name:'Order History',
link:'OrderHistory'
},{
id:'3',
name:'Payment',
link:''
},{
id:'4',
name:'Recharge',
link:''
},{
id:'5',
name:'Help',
link:''
},{
id:'6',
name:'Logout',
link:''
}]
}
render () {
return (
<View style={styles.container} >
<DrawerHeader navigation={this.props.navigation}/>
<DrawerMenu
navigation={this.props.navigation}
menuItems={this.state}
style={{ marginTop: 106/3}}
/>
</View>
);
}
}
export default SideMenuLayout;
const styles = StyleSheet.create({
container:{
flex:1,
backgroundColor: "#ffffff",
}
});
Drawer Header code goes here. Here I am trying to close the navigation drawer.
import React, {Component} from 'react';
import {Text, View, StyleSheet,Image,TouchableOpacity} from 'react-native';
import { FontAwesome } from '#expo/vector-icons';
import { DrawerActions, StackNavigator } from 'react-navigation';
const DrawerHeader = (props)=> {
const { navigate } = props.navigation;
return (
<View style={{backgroundColor: '#d61822',width:DRAWER_CONTAINER_WIDTH/3,height:DRAWER_CONTAINER_HEIGHT/3 }}>
<View style={styles.titleContainer}>
<View style={{ marginLeft:20, backgroundColor:'#d61822',height:40 }}>
<Text style={{fontSize:28,fontStyle:'italic',color:'#ffff',fontWeight:'bold'}}>
Prabhuji Online
</Text>
</View>
<View style={{ marginLeft:35,backgroundColor:'#d61822',width: 50, height: 40,paddingRight:10,alignItems:'center',justifyContent:'center' }}>
<TouchableOpacity onPress={()=>navigate.dispatch(DrawerActions.closeDrawer())}>
<Text style={{fontSize:20,color:'#ffff',}}>
<FontAwesome
style={{ alignSelf: 'flex-end'}}
name="times"
size={18}
color="#ffffff"
/>
</Text>
</TouchableOpacity>
</View>
</View>
<View style={styles.fakeContainer}>
</View>
<View style={{
position:'absolute',
top: 170/3,
marginLeft:20,
width:220/3,
height:220/3,
backgroundColor:'#fffcf9',
borderRadius:(220/3)/2,
justifyContent:'center',
alignContent:'center',
alignItems:'center',
shadowColor: "#000",
shadowOffset: {
width: 0,
height: 5,
},
shadowOpacity: 0.25,
shadowRadius: 6.27,
elevation: 7,
}}>
<Image
tintColor='red'
style={{
width: 111/3,
height: 111/3,
}}
source={require('../../../assets/place_order.png')}/>
</View>
</View>
);
}
export default DrawerHeader;
const styles = StyleSheet.create({
titleContainer:{
backgroundColor: '#d61822',
flexDirection: 'row',
height:TITLE_CONTAINER_HEIGHT/3,
marginTop: 50/3,
},
fakeContainer:{
position:'relative',
height:FAKE_CONTAINER_HEIGHT/3,
backgroundColor: '#ffffff',
//backgroundColor: 'yellow',
}
});
Can any one please tell me what is going wrong here?
I have also tried navigate.closeDrawer(). But same error is giving.

Instead of using the navigate call, you need to dispatch the action like this: this.props.navigation.dispatch(*your action here*), as described in the docs: https://reactnavigation.org/docs/en/navigation-prop.html#dispatch-send-an-action-to-the-router

Related

How to fix react navigation displacing my component from top of screen?

I am working on a react native application and am trying to understand how to deal with react navigation as it affects my styling. Essentially when I navigate to a page, react navigation's top arrow with header is displacing my components (I'd like to move my black header bar up and use react navigation's arrow ideally):
I have react navigation set up in the following manner:
App.js
const ProfileNavigator = createStackNavigator({
//Profile: { screen: Profile},
QR: { screen: GenerateQR },
EditAccount: { screen: EditAccount }
});
const AppNavigator = createSwitchNavigator({
tabs: bottomTabNavigator,
profile: ProfileNavigator
})
const AppContainer = createAppContainer(AppNavigator);
I have a header component I put together for styling that I use on top of each page:
pageTemplate
import React, {Component} from 'react';
import {Text,View, StyleSheet} from 'react-native';
import { TouchableOpacity } from 'react-native-gesture-handler';
import { Ionicons } from '#expo/vector-icons';
class PageTemplate extends Component {
render() {
return (
<View
style={{
flexDirection: 'row',
height: 130,
alignSelf: 'stretch',
width: '100%'
}}>
<View style={{backgroundColor: 'black', alignSelf: 'stretch',width: '100%'}} />
<View style=
{{position:'absolute',
marginTop: '16%',
marginLeft: '3%',
display: 'flex',
flexDirection: 'row',
flex:1
}}>
<TouchableOpacity onPress={this.props.navigate}>
<Ionicons name="ios-arrow-dropleft" size={32} color="white" />
</TouchableOpacity>
</View>
<Text
style={{
position: 'absolute',
marginTop: '15%',
marginLeft: '12%',
color: 'white',
fontSize: 30}}
>
{this.props.title}
</Text>
</View>
);
}
}
export default PageTemplate;
I have a tab called profile which navigates through a list item to get to an account edits page:
Profile
import React from 'react';
import { StyleSheet, Text, View, Image, TouchableOpacity, TouchableHighlight } from 'react-native';
import { Ionicons } from '#expo/vector-icons';
import { List, ListItem } from 'react-native-elements'
import GenerateQR from './generateQR';
import PageTemplate from './smallComponents/pageTemplate';
import pic from '../assets/bigRate.png'
export default class Profile extends React.Component {
render() {
const { navigate } = this.props.navigation;
navigateBack=()=>{
navigate('Queue')
}
return(
<React.Fragment>
<PageTemplate title={'Profile Settings'} navigate={navigateBack} />
{/*<Image source={pic} />*/}
{/** Frst Section */}
<View style={{
//backgroundColor:'blue'
}}>
<Text style={styles.section}>Account Information</Text>
</View>
<TouchableOpacity
onPress={()=>{navigate('EditAccount')}}
style={{position: 'absolute',
marginTop:'32%',
flex:1,
flexDirection: 'row',
flexWrap: 'wrap'}}>
<View style={{
marginLeft:'5%',
flex:1,
flexDirection: 'row',
flexWrap: 'wrap',
justifyContent: 'flex-start',
//backgroundColor:'yellow',
alignItems: 'center',
//borderRadius:50,
//height:'60%'
}} >
<Ionicons style={{marginLeft:'20%'}} name="ios-person" size={72} />
</View>
<View style={{paddingTop:50,
marginRight:'40%',
flex:2,
flexDirection: 'row',
flexWrap: 'wrap',
//backgroundColor: 'red'
}}
>
<Text>Sylvester Stallone</Text>
<Text>+1 646-897-0098</Text>
<Text>SlyLone#gmail.com</Text>
</View>
</TouchableOpacity>
{/**add line section */}
</React.Fragment>
);
}
}
const styles = StyleSheet.create({
option : {
//position: 'absolute',
marginLeft:'7%',
alignSelf: 'stretch',
width: '100%',
height: '15%',
//flexWrap: 'wrap',
justifyContent:'space-between',
//padding:20
},
section : {
fontSize:20,
marginLeft:'5%'
}
})
/**
*
*
*
<View style={styles.option}>
<Ionicons name="ios-gift" size={32} />
<TouchableHighlight>
<Text>Rewards</Text>
</TouchableHighlight>
</View>
*
*/
Ideally it be nice to drop the arrow icon and move the header up keeping react-navigations arrow.
If you want to get rid of the arrows, you can create your own headers.
Example
class LogoTitle extends React.Component {
render() {
return (
<Image
source={require('#expo/snack-static/react-native-logo.png')}
style={{ width: 30, height: 30, alignSelf:"center" }}
/>
);
}
}
class HomeScreen extends React.Component {
static navigationOptions = {
// headerTitle instead of title
headerTitle: () => <LogoTitle />,
headerLeft: () => (
<Button
onPress={() => alert('This is a button!')}
title="back"
color="#fff"
/>
),
};

How to navigate to other page after click on button in react native?

I am an beginner in react native.I want to display home page after logged in.I have install react-navigator using npm install and I have tried below code.
But I am getting below error, I tried to solve this. Still I have the error.
In App.js
//This is an example code for Bottom Navigation//
import React, { Component } from 'react';
//import react in our code.
import { Text, View, TouchableOpacity, StyleSheet } from 'react-native';
//import all the basic component we have used
import { createStackNavigator, createAppContainer } from 'react-navigation';
export default class App extends Component {
render() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text style={{ marginTop: 50, fontSize: 25 }}>Setting!</Text>
<View
style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<TouchableOpacity
style={styles.button}
onPress={() => this.props.navigation.navigate('Two')}>
<Text>Go to Home Tab</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.button}
onPress={() => this.props.navigation.navigate('Two')}>
<Text>Open Detail Screen</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.button}
onPress={() => this.props.navigation.navigate('Two')}>
<Text>Open Profile Screen</Text>
</TouchableOpacity>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
button: {
alignItems: 'center',
backgroundColor: '#DDDDDD',
padding: 10,
width: 300,
marginTop: 16,
},
});
Can anyone assist me to solve this?
You can do it as following:
import React from "react";
import { View, Text } from "react-native";
class HomeScreen extends React.Component {
render() {
return (
<View style={{ flex: 1, alignItems: "center", justifyContent: "center" }}>
<Text>Home Screen</Text>
</View>
);
}
}
class LoginScreen extends React.Component {
render() {
return (
<View style={{ flex: 1, alignItems: "center", justifyContent: "center" }}>
<Text>Login Screen</Text>
<Button
title="Go to Home"
onPress={() => this.props.navigation.navigate('Home')}
/>
</View>
);
}
}
on App.js,
import React from 'react';
import { HomeScreen, LoginScreen } from '..'// should set the proper path.
const AppNavigator = createStackNavigator({
Login: LoginScreen,
Home: HomeScreen
});
const App = () => {
return <AppNavigator />;
}
export default App;

React native align icon and text

for the love of God, every styling i put on the stylesheet doesn't change anything.
i tried style the view, sectionheader & sectionbox but no luck
i want to align 4 icons in the boxsection and text below then as such, please any help would be appreciated.
export default class HomePage extends Component {
render() {
return (
<View>
<SectionHeader title={'Food'} />
<View >
<SectionBox >
<Icon style={styles.icons} name="icon name" size={50} />
<Icon style={styles.icons} name="icon name" size={50} />
<Icon style={styles.icons} name="icon name" size={50} />
<Icon style={styles.icons} name="icon name" size={50} />
<Text style={styles.sectiontext}>burgers</Text>
</SectionBox>
</View>
const styles = StyleSheet.create({
icons: {
flexDirection: 'row',
paddingTop: 7,
paddingLeft: 5,
},
sectiontext: {
fontSize: 15,
fontWeight: 'bold',
paddingLeft: 5,
alignItems: 'center',
}
});
For the icons-containing-box you would need to indicate flexDirection and flexWrap, not directly on the icon's style. Then to get the text below each icon you need to wrap icon and text in its own view and give that 'column' direction.
import * as React from 'react';
import { Text, View, StyleSheet } from 'react-native';
import { Ionicons } from '#expo/vector-icons';
import { Constants } from 'expo';
const ICON_SIZE = 70;
const FONT_SIZE = 18;
const getItem = () => (
<View style={styles.iconStyle}>
<Ionicons name="md-checkmark-circle" size={ICON_SIZE} color="green" />
<Text style={styles.textStyle}>name</Text>
</View>
);
export default class App extends React.Component {
render() {
return (
<View style={styles.container}>
<View style={styles.iconContainer}>
{getItem()}
{getItem()}
{getItem()}
{getItem()}
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
iconContainer: {
width: ICON_SIZE * 2,
flexDirection: 'row',
flexWrap: 'wrap',
},
iconStyle: {
flexDirection: 'column',
alignItems: 'center',
padding: 5,
},
textStyle: {
fontSize: FONT_SIZE,
},
});
You need a view for each group of icon and text with a flexDirection: 'column' and one another view for each row (or column), like the example below:
https://snack.expo.io/HJY7IWsFm
Other option is to use a GridView lib:
https://github.com/saleel/react-native-super-grid

Progress Dialog in ReactNative

I'm pretty new to ReactNative world. Im struggling to find an api or a library that shows the Progress Dialog as below in React Native. I believe ActivityIndicator can be used, but it does not show as overlay. Can anyone help me how can I show as an overlay using styles or if there is good library to make this.
Thanks
Here is the code to Open Prgressbar:
import React from 'react';
import { Modal, View, Text, ActivityIndicator, Button } from 'react-native';
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = { isProgress: false }
}
openProgressbar = () => {
this.setState({ isProgress: true })
}
render() {
return (
this.state.isProgress ?
<CustomProgressBar />
:
<View style={{ flex: 1, backgroundColor: '#fff', alignItems: 'center', justifyContent: 'center' }}>
<Button title="Please click here to Open ProgressBar" onPress={this.openProgressbar} />
</View>
);
}
}
const CustomProgressBar = ({ visible }) => (
<Modal onRequestClose={() => null} visible={visible}>
<View style={{ flex: 1, backgroundColor: '#dcdcdc', alignItems: 'center', justifyContent: 'center' }}>
<View style={{ borderRadius: 10, backgroundColor: 'white', padding: 25 }}>
<Text style={{ fontSize: 20, fontWeight: '200' }}>Loading</Text>
<ActivityIndicator size="large" />
</View>
</View>
</Modal>
);
Expo url for live demo
https://snack.expo.io/#jitendra.mca13/progress-bar-demo
I would approach this by using the React Native Modal component with two Views.
This solution is a React solution and not native, so you will need to style your Modal accordingly for each platform.
import React from 'react';
import {
Modal,
View,
StyleSheet,
Text,
ActivityIndicator
} from 'react-native';
const ProgressDialog = ({ visible }) => (
<Modal
visible={visible}
>
<View style={styles.container}>
<View style={styles.content}>
<Text style={styles.title}>Please Wait</Text>
<View style={styles.loading}>
<View style={styles.loader}>
<ActivityIndicator size="large" />
</View>
<View style={styles.loadingContent}>
<Text>Loading</Text>
</View>
</View>
</View>
</View>
</Modal>
);
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'rgba(0, 0, 0, .5)',
alignItems: 'center',
justifyContent: 'center',
},
content: {
padding: 35,
backgroundColor: 'white'
},
title: {
fontSize: 18,
fontWeight: 'bold',
},
loading: {
flexDirection: 'row',
alignItems: 'center',
},
loader: {
flex: 1,
},
loadingContent: {
flex: 3,
fontSize: 16,
paddingHorizontal: 10,
}
})
export default ProgressDialog;
Here's a demo on Expo, of course you will probably want to tweak the CSS.
Android & iOS solution
Create a directory called ProgressDialog
Create index.ios.js and index.android.js
Paste the above code into both index.ios.js and index.android.js
Make CSS changes for iOS
You can use the below npm package which is a very easy and attractive loader with many options.
https://github.com/maxs15/react-native-spinkit
import React from 'react';
import { StyleSheet, View } from "react-native";
import Spinner from "react-native-spinkit";
export default LoadingCmpBig = props => {
return (
<View style={styles.container}>
<StatusBar barStyle="default" />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
//backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
}
});
You can use this component and use it where you want to show the Progress. You just have to maintain the state for visible the loading or not in your render function of the component.

React-native elements search bar ref to use focus() method for instance is undefined

I followed the doc of the react-native-elements library but I get this.search as an undefined object...
searchbar react-native-elements
class SearchBarTest extends Component {
componentDidMount()
{
this.search.focus()//search is undefined
}
render(){
<SearchBar
ref={search => this.search = search}
...
/>
}
}
Any idea how to make this working?
EDIT:
Adding full context of the code.
The idea is having a component with a header and body. The header has an optional search bar or a title and two buttons depending on the props search.
If search props is true, then I display the searchBar.
PARENT COMPONENT:
import React, {Component} from 'react';
import {StyleSheet, View, Text, TouchableWithoutFeedback, Keyboard} from 'react-native';
import Icon from 'react-native-vector-icons/Ionicons';
import DismissableKeyboardContainer from '../../components/DismissableKeyboardContainer';
export default class Search extends Component {
static navigationOptions = () => {
return {
tabBarIcon: ({tintColor}) => (
<Icon name="ios-search-outline" size={25} color={tintColor}/>
)
}
};
render() {
someMethod = () => {
console.log('hello');
}
return (
<DismissableKeyboardContainer search={true}>
<View style={{flex: 1, alignItems: 'center'}}>
<Text>Hello world</Text>
</View>
</DismissableKeyboardContainer>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
}
});
COMPONENT where the actual searchBar component is used:
import React, { Component} from 'react';
import { Keyboard, TouchableWithoutFeedback, TouchableOpacity, View, Text, StyleSheet} from 'react-native';
import { SearchBar } from 'react-native-elements'
import Icon from 'react-native-vector-icons/Ionicons';
import PropTypes from 'prop-types';
class DismissableKeyboardContainer extends Component {
static defaultProps = {
title: '',
search: false,
buttonLeft: '',
buttonRight: '',
borderShadow: true,
headerStyle:{}
};
componentDidMount()
{
}
render() {
let { title, search, buttonLeft, buttonRight, headerStyle, borderShadow } = this.props;
return (
<TouchableWithoutFeedback onPress={() => Keyboard.dismiss()}>
<View style={{ flex: 1 }}>
<View style={[styles.headerContainer, borderShadow ? styles.borderShadow : '', headerStyle]}>
{
!search && <View style={{position: 'absolute', padding: 10, bottom: 0, flex: 1, flexDirection: 'row', alignItems: 'center', justifyContent: 'center'}}>
<TouchableOpacity style={{ flex: 0.2, alignItems: 'center'}}>
{
buttonLeft != "" && <Icon name={buttonLeft} size={25} color="grey" />
}
</TouchableOpacity>
<View style={{ flex: 1, alignItems: 'center' }}>
<Text style={styles.title}>{title}</Text>
</View>
<TouchableOpacity style={{ flex: 0.2, alignItems: 'center' }}>
{
buttonRight != "" && <Icon name={buttonRight} size={25} color="grey" />
}
</TouchableOpacity>
</View>
}
{
search && <SearchBar
ref={search => this.search = search}
containerStyle={{ backgroundColor: 'transparent', borderTopWidth: 0, borderBottomWidth: 0 }}
inputStyle={{ backgroundColor: 'white' }}
lightTheme
onChangeText={someMethod}
placeholder='Type Here...'
/>
}
</View>
<View style={{ flex: 1, backgroundColor: 'transparent'}}>
{this.props.children}
</View>
</View>
</TouchableWithoutFeedback>
);
}
}
const styles = StyleSheet.create({
headerContainer: {
flex: 0.12,
justifyContent: 'flex-end',
backgroundColor: 'white' ,
},
borderShadow: {
borderColor: '#ddd',
borderBottomWidth: 0,
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.2,
shadowRadius: 1,
elevation: 1,
},
title: {
fontSize: 18,
fontWeight: 'bold'
}
});
DismissableKeyboardContainer.propTypes = {
title: PropTypes.string.isRequired,
search: PropTypes.bool.isRequired,
buttonLeft: PropTypes.string.isRequired,
buttonRight: PropTypes.string.isRequired,
headerStyle: PropTypes.any,
};
export default DismissableKeyboardContainer;
I think I found the issue. As my SearchScreen is part of a TabBar from react-navigation, this.search.focus() error was appearing at the initial loading of the app. The Search screen being the second tab of the tabBar, I guess this is the reason why search couldn't be found as the screen was not active.
Found this answer: Trigger event on tabBar screen display
Which helped me to launch the this.search.focus() only when the screen Search is called under the componentDidUpdate() method
Please see code below:
1- First on my root navigator, I track react-navigation screen changes with onNavigationStateChange and screenProps
<Root
onNavigationStateChange={(prevState, currentState, action) => {
let currentScreen = action.routeName;
this.setState({ currentScreen })
}}
screenProps={{ currentScreen: this.state.currentScreen }}
/>
2- Then on my Parent component, I pass the currentScreen prop from I setup above in react-navigation
<DismissableKeyboardContainer search={true} currentScreen={this.props.screenProps.currentScreen}>
<View style={{flex: 1, alignItems: 'center'}}>
<Text>Hello world</Text>
</View>
</DismissableKeyboardContainer>
3- Now, I'm checking the screen being displayed and launch this.search.focus() only if the screen Search is displayed inside my DismissableKeyboardContainer child component.
componentDidUpdate() {
this.props.currentScreen === "Search" ? this.search.focus() : ''
}