react navigation full screen modal from windowed component - react-native

How do you open a full screen modal from a windowed component in react navigation?
The opened modal has always the same size as the windowed component, from which the modal was navigated to.
I created a snack expo to show the problem here: https://snack.expo.io/Bk0N69FwX
This is just a basic example to show the problem, in my actual project the components are nested many times, so I cannot easily set the modal in the top level StackNavigator and navigate to it from a deeply nested component.
import * as React from 'react';
import { Text, View, StyleSheet, Button } from 'react-native';
import { Constants } from 'expo';
import { createStackNavigator } from 'react-navigation';
// modal that should be rendered full screen
class Modal extends React.Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.text}>
This should be a full screen modal
</Text>
</View>
)
}
}
// windowed component, from which the modal will be navigated to
class NestedComponent extends React.Component {
render() {
return (
<View style={styles.nestedContainer}>
<Text style={styles.text}>
nested component
</Text>
<Button
onPress={() => this.props.navigation.navigate('modal')}
title="open modal"
/>
</View>
)
}
}
const ModalStackComponent = () => {
return (
<ModalStackNavigator />
)
}
const ModalStackNavigator = createStackNavigator(
{
nestedComponent: {
screen: NestedComponent,
navigationOptions: {
header: null,
},
},
modal: {
screen: Modal,
},
},
{
mode: 'modal',
}
)
export default class App extends React.Component {
render() {
return (
<View style={styles.container}>
// some stub container to limit screen size for nested component
<View style={styles.upperComponentContainer}>
<Text style={styles.text}>
upper component
</Text>
</View>
<ModalStackComponent />
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'stretch',
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
},
upperComponentContainer: {
flex: 1,
backgroundColor: 'lightgrey',
justifyContent: 'center',
},
nestedContainer: {
flex: 1,
justifyContent: 'center',
},
text: {
textAlign: 'center',
fontSize: 20,
color: 'black',
},
});

For your requirement, you can use React native Modals.
https://facebook.github.io/react-native/docs/0.56/modal

Related

How to pass new params to previous screen in react native?

I have a flatlist of movies when a user clicks on it, it passes param to movie details screen and movie detail is shown then that screen has flatlist of similar movies when user selects any of it, basically new params should be passed to movie details screen but no, it is just working as if i am tapping on back button....
onPress={() =>
this.props.navigation.navigate('MovieDetails', {
selectedItem: item,
})
} // Passing params to movie details screen
console.log(this.props.navigation.getParam('selectedItem')) //receiving params in movie details screen
Check this below example. Hope this will help you.
import * as React from 'react';
import { Button, View, Text } from 'react-native';
import { createAppContainer } from 'react-navigation';
import { createStackNavigator } from 'react-navigation-stack';
class HomeScreen extends React.Component {
render() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text style={{ fontSize: 20, marginBottom: 10 }}>Home Screen</Text>
<Button
title="Go to Details"
onPress={() =>
this.props.navigation.navigate('Details', {
name: 'this params from homescreen',
})
}
/>
</View>
);
}
}
class DetailsScreen extends React.Component {
render() {
console.log('screen', this.props.navigation.state);
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text style={{ fontSize: 20, marginBottom: 10 }}>
{this.props.navigation.state.params.name}
</Text>
<Button
title="Go back"
onPress={() => this.props.navigation.goBack()}
/>
</View>
);
}
}
const RootStack = createStackNavigator({
Home: HomeScreen,
Details: DetailsScreen,
});
export default createAppContainer(RootStack);
Feel free for doubts.

I need to show Alert modal in every screen when intenet is down

I need to show NetAlert modal in every screen when intenet is down. I have created a NetAlertModal component for that . I am not sure where to render this component . I am using react navigation Switch navigator. If I am rendering as below it is not showing login screen.
I am new to react native so please help.
Below is my code
/***App.js*/
render() {
return (
<Provider store={store}>
<PersistGate>
<Fragment>
<StatusBar barStyle="dark-content" />
<SafeAreaView
style={styles.safeArea}
forceInset={{bottom: 'never', top: 'never'}}>
<NetAlertModal /> <------ Need to show this
<RootNav
ref={navigatorRef => {
NavigationService.setTopLevelNavigator(navigatorRef);
}}
/>
</SafeAreaView>
</Fragment>
</PersistGate>
</Provider>
);
}
}
/*rootNav.js*/
const RootNav = createSwitchNavigator(
{
Drawer: DrawerNavigator,
Auth: AuthStack,
},
{
initialRouteName: 'Auth',
},
);
export default createAppContainer(RootNav);
*/AuthStack.js*/
import {createStackNavigator} from 'react-navigation';
import Login from '../components/login/Login';
import Verify from '../components/verify/Verify';
const rootConfiguration = {
loginPage: {screen: Login},
verifyPage: {screen: Verify},
};
const stackNavigatorConfiguration = {
initialRouteName: 'loginPage',
headerMode: 'none',
defaultNavigationOptions: {
headerTintColor: '#ffeb3b',
headerTitleStyle: {
fontWeight: 'bold',
flex: 1,
textAlign: 'center',
},
},
};
export const AuthStack = createStackNavigator(
rootConfiguration,
stackNavigatorConfiguration,
);
Try this below example in your app.js which I create using #react-native-community/netinfo library
import React, { Component } from 'react';
import NetInfo from "#react-native-community/netinfo";
import { View, Text, Modal } from 'react-native';
class App extends Component {
constructor(props) {
super(props);
this.state = {
isConnected: true,
};
}
componentDidMount() {
NetInfo.isConnected.addEventListener('connectionChange', this.handleConnectivityChange);
}
componentWillUnmount() {
NetInfo.isConnected.removeEventListener('connectionChange', this.handleConnectivityChange);
}
handleConnectivityChange = isConnected => {
this.setState({ isConnected });
};
render() {
return (
<View style={{ flex: 1 }}>
<View style={{ flex: 1 }}>
{/* your app */}
</View>
{
!this.state.isConnected &&
<Modal
visible={!this.state.isConnected}
transparent={true}
animationType='slide'
>
<View style={styles.modelStyle}>
<View style={styles.modelWrapperStyle}>
<Text style={{ textAlign: 'center' }}>{global.strings.oops}</Text>
<Text style={{ textAlign: 'center' }}>{global.strings.internetConnection}</Text>
</View>
</View>
</Modal>
}
</View>
);
}
}
const styles = {
modelStyle: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'rgba(0, 0, 0, 0.5)'
},
modelWrapperStyle: {
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#e3dfde',
padding: 20,
width: '90%',
borderRadius: 20
},
};
export default App;
Change this according to your requirement. Feel free for doubts.
import { NetInfo } from 'react-native';
NetInfo.isConnected.fetch().then(isConnected => {
if(isConnected)
{
console.log('Internet is connected');
}
})
use above code as a HOC or make it global for your root file

Can't Wrap Navigator in SafeAreaView

When running the app on the iPhone X simulator the Material Top Tab Navigator cuts into the notch and bottom button.
To fix this I have tried to implement the SafeAreaView before applying the App Container and to wrap each individual screen in SafeAreaViews. This works to keep the text away from these areas but not the navigator.
import React, { Component } from 'react';
import { Text, View } from 'react-native';
import { createAppContainer, createMaterialTopTabNavigator, SafeAreaView } from 'react-navigation';
class Calculator extends Component {
render() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Calculator!</Text>
</View>
);
}
}
class Camera extends Component {
render() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Camera!</Text>
</View>
);
}
}
class Solution extends Component {
render() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Solution!</Text>
</View>
);
}
}
const TabNavigator = createMaterialTopTabNavigator(
{
Calculator,
Camera,
Solution
},
{
tabBarPosition: 'bottom',
}
);
const AppContainer = createAppContainer(TabNavigator);
class App extends Component {
render() {
return (
<SafeAreaView>
<AppContainer/>
</SafeAreaView>
);
}
}
export default App;
When running this application, no errors are present. However, nothing renders. What I would expect is a tab navigator renders with three tabs that doesn't cut under the notch or bottom button.
give SafeAreaView a size
<SafeAreaView style={{ flex: 1 }}>
<AppContainer/>
</SafeAreaView>
if AppContainer still spreads full screen,
change import { SafeAreaView } from 'react-navigation'
to import { SafeAreaView } from 'react-native'
You need to provide flex: 1 as style to the SafeAreaView Component
<SafeAreaView style={{flex: 1}}>
{/* Component here */}
</SafeAreaView>

Custom React Drawer Navigation

i'm currently trying to implement custom component to show the icon i've.
i got no error when rendering it , but 2 of list of screen didn't shows up. am i need to do something with styling or there's a problem with my code
if anyone could inspect my code that would be awesome
this is my error
here are my code
App.js
import React from 'react';
import {
StyleSheet,
View,
SafeAreaView,
ScrollView,
Dimensions,
Image,
Text
} from 'react-native';
import {
createDrawerNavigator,
DrawerItems
} from 'react-navigation';
import HomeScreen from './screen/HomeScreen';
import SettingsScreen from './screen/SettingsScreen';
export default class App extends React.Component {
render () {
return (
<AppDrawerNavigator />
);
}
}
const CustomDrawerComponent = ( props ) => (
<SafeAreaView style={{flex: 1}}>
<ScrollView>
<View style={{height:150,backgroundColor:'white',alignItems: 'center', justifyContent: 'center' }}>
<Image
source={require('./img/cs.png')}
style={{height:120, width:120, borderRadius: 20}}
/>
</View>
</ScrollView>
</SafeAreaView>
)
const AppDrawerNavigator = createDrawerNavigator ({
Home: HomeScreen,
Settings: SettingsScreen
},{
contentComponent: CustomDrawerComponent
})
const styles = StyleSheet.create({
container: {
flex: 0,
color: '#fff',
alignItems: 'center',
justifyContent: 'center'
}
});
Homescreen.js
import React, { Component } from 'react';
import {
StyleSheet,
Text,
View
} from 'react-native';
class HomeScreen extends Component {
render () {
return (
<View style={styles.container}>
<Text>Home</Text>
</View>
);
}
}
export default HomeScreen ;
const styles = StyleSheet.create({
container: {
flex: 1,
color: '#fff',
alignItems: 'center',
justifyContent: 'center'
}
});
According to the official doc, your Drawer Navigator has to be defined like:
const AppDrawerNavigator = createDrawerNavigator({
Home: {
screen: HomeScreen,
},
Settings: {
screen: SettingsScreen,
}
});
You're not assigning an object with a prop screen to each custom screen.
For more details take a look at doc.
as I understand, you need to add DrawerItems to your drawer.
import { DrawerItems, SafeAreaView } from 'react-navigation';
const CustomDrawerComponent = ( props ) => (
<SafeAreaView style={{flex: 1}}>
<ScrollView>
<View style={{height:150,backgroundColor:'white',alignItems: 'center', justifyContent: 'center' }}>
<Image
source={require('./img/cs.png')}
style={{height:120, width:120, borderRadius: 20}}
/>
</View>
<DrawerItems {...props} />
</ScrollView>
</SafeAreaView>
)

How to change state value in react native?

I have problem in changing value of state.It gives mi following error
"Undefine is not a function(evaluating '
this.setState({
switchValue:false
})')"
I have search on stack overflow but the solution is not work for me.
import React, { Component } from 'react';
import {
Alert,
AppRegistry,
StyleSheet,
Text,
View,
Switch
} from 'react-native';
export default class AwesomeProject extends Component {
constructor(props) {
super(props);
this.state = {switchValue: true};
// Toggle the state every second
}
_onPressButton() {
this.setState({
switchValue: false
});
}
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>
Welcome to React Native!
</Text>
<Switch
onValueChange={this._onPressButton}
value={this.state.switchValue }
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
});
AppRegistry.registerComponent('AwesomeProject', () => AwesomeProject);
The this inside _onPressButton is not referencing the correct reference. On that case, this inside that _onPressButton is actually reference the button. You can either do this two ways.
<Switch
onValueChange={this._onPressButton.bind(this)}
value={this.state.switchValue }
/>
Or
<Switch
onValueChange={() => this._onPressButton()}
value={this.state.switchValue }
/>