I'm experiencing a performance issue with DrawerNavigator with the following code.
class App extends Component {
componentDidMount(){
var salt = bcrypt.genSaltSync(10);
var hash = bcrypt.hashSync("StrToHash", salt);
}
render() {
console.log("rendering");
return (
<View style={styles.container}>
<Text style={styles.welcome}>
Welcome to React Native!
</Text>
<Text style={styles.instructions}>
To get started, edit App.js
</Text>
<Button
onPress={ () => {} }
title="Learn More"
color="#841584"
accessibilityLabel="Learn more about this purple button"
/>
</View>
);
}
}
Home.navigationOptions = {
drawerLabel: 'Home',
drawerIcon: ({ tintColor }) => (
<MaterialIcons
name="move-to-inbox"
size={24}
style={{ color: tintColor }}
/>
),
};
App.navigationOptions = {
drawerLabel: 'App',
drawerIcon: ({ tintColor }) => (
<MaterialIcons name="drafts" size={24} style={{ color: tintColor }} />
),
};
export default DrawerExample = DrawerNavigator(
{
Home: {
path: '/',
screen: Home,
},
App: {
path: '/sent',
screen: App,
},
},
{
drawerOpenRoute: 'DrawerOpen',
drawerCloseRoute: 'DrawerClose',
drawerToggleRoute: 'DrawerToggle',
initialRouteName: 'Home',
contentOptions: {
activeTintColor: '#e91e63',
},
}
);
I don't understand why, each time I put some logic in componentDidMount() DrawerNavigator start to be laggy and does not work properly on Android. I think I'm missing something but I don't know what. If I have to put some logic in a component, where should I put the logic code ? If someone would like to enlighten me:)
use prop detachInactiveScreens={false} in <Drawer.Navigator>
but you also need to
import { enableScreens } from 'react-native-screens'
it solved my lagging issue of drawer.
Related
Hello guys so now I'm trying to create to do list application using react native and I'm able to make the user add task. Now I want the user to be able to update the Task status by pressing some button (touchableOpacity). I want the touchableOpacity to change color from red to green (if the task is finished) and turn the color from green to red if the task haven't finished. Can someone help me please ? I want to use state for this. I already prepare some state for it.
Here's my code:
const Task = (props) => {
const[pressed, setPressed] = useState(false);
const onPressHandler = () =>{
setPressed(!pressed);
};
return (
<View style={styles.wrapper}>
<Text style={styles.taskList}>{props.text}</Text>
<TouchableOpacity style={styles.taskStatus} onPress={() => onPressHandler()}>
<Text style={styles.statusText}>On Going</Text>
</TouchableOpacity>
</View>
)
}
Hey instead of using TouchableOpacity You can also use Pressable
<Pressable
style={({ pressed }) => [
{
backgroundColor: pressed
? 'rgb(210, 230, 255)'
: 'white'
},
]}>
<Text style={getTextStyle()}>{text}
</Text>
</Pressable>
ref: https://reactnative.dev/docs/pressable
you can only change activeOpacity property which defaults to 0.2. If you want you Touchable component to tint with some other color, then you will have to create custom TouchableComponent using TouchableHighlight
You can add some inline style your TouchableOpacity by comparing the state
<TouchableOpacity style=[{
backgroundColor: pressed ? 'green' : 'red
}, styles.taskList]
onPress={() => onPressHandler()}
>
<Text style={styles.statusText}>On Going</Text>
</TouchableOpacity >
const Task = (props) => {
const [text, setText] = useState('Update')
const [taskCompleted, setTaskCompleted] = useState(null)
const onPressHandler = () => {
setText('On Going...')
setTimeout(() => {
//Based on your task set status
setText('Success')
setTaskCompleted(true)
//Error sample code
// setText('Error')
// setTaskCompleted(false)
}, 2000)
}
const getTouchableOpacityStyle = () => {
if (taskCompleted === null) {
return styles.touchableOpacityDefaultstyle
}
return taskCompleted ? styles.touchableOpacityStyleOnComplete : styles.touchableOpacityStyleOnError
}
const getTextStyle = () => {
if (taskCompleted === null) {
return styles.textDefaultStyle
}
return styles.textStyleOnTaskExecuted
}
return (
<View style={styles.container}>
<Text>{props.text}</Text>
<TouchableOpacity onPress={onPressHandler} style={getTouchableOpacityStyle()}>
<Text style={getTextStyle()}>{text}</Text>
</TouchableOpacity>
</View>
)
}
const styles = StyleSheet.create({
container: {
justifyContent: 'center',
alignItems: 'center'
},
touchableOpacityDefaultstyle: {
backgroundColor: 'grey',
padding: 10
},
touchableOpacityStyleOnComplete: {
backgroundColor: 'green',
padding: 10
},
touchableOpacityStyleOnError: {
backgroundColor: 'red',
padding: 10
},
textDefaultStyle: {
color: 'black'
},
textStyleOnTaskExecuted: {
color: 'white'
}
})
export default Task
I am very new to react native and this is my 1st application my org has given me to do a PoC for the same.
My requirement is i have to develop an app with
Login screen -----> Navigation Drawer(1) screen Name-- workProcessor and 2) Operation Analytics)
I am able to achieve screen at 2 different level's
i.e i am able to design Login screen and i am able to design workprocessor and operation analytics screen and switch between them
I am not able to Integrate my login screen and on click of login i should navigate to Navigation-drawer screen
My files are :
Login.js
import React from 'react';
import {
ScrollView,
Text,
TextInput,
View,
Button,
StyleSheet
} from 'react-native';
import Logo from './Logo';
import Form from './Form';
export default class Login extends React.Component {
render() {
return (
<View style={styles.container}>
<Logo></Logo>
<Form type = "Login"></Form>
<View style ={styles.workSpaceText}>
<Text style = {styles.workSpaceText}> Change WorkSpace ?</Text>
</View>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
backgroundColor: '#455a64',
flex: 1,
alignItems: 'center',
justifyContent: 'center'
},
workSpaceText: {
flexGrow:1,
justifyContent:'center',
alignItems:'center',
},
workSpaceText: {
fontSize: 15,
marginVertical:15,
color: 'rgba(255,255,255,0.7)'
}
});
Form.js
import React from 'react';
import { StyleSheet, TextInput, View, Image, TouchableOpacity, Text } from "react-native";
import { useNavigation } from '#react-navigation/native';
// import { Actions } from 'react-native-router-flux';
const Form = () => {
const navigation = useNavigation();
loginMove= ()=>{
navigation.navigate('Landing');
}
return (
<View style={styles.container}>
<TextInput style={styles.inputBox}
underlineColorAndroid='rgba(0,0,0,0)'
placeholder="Username"
placeholderTextColor='#ffffff'
/>
<TextInput style={styles.inputBox}
underlineColorAndroid='rgba(0,0,0,0)'
placeholder="Password"
placeholderTextColor='#ffffff'
/>
<TouchableOpacity style={styles.button} onPress={loginMove}>
<Text style={styles.buttonText}>Login</Text>
</TouchableOpacity>
</View>
);
}
export default Form;
const styles = StyleSheet.create({
container: {
flexGrow: 1,
justifyContent: 'center',
alignItems: 'center'
},
inputBox: {
width: 300,
backgroundColor: 'rgba(255,255,255,0.5)',
borderRadius: 25,
paddingHorizontal: 16,
fontSize: 16,
color: '#ffffff',
marginVertical: 10
},
button: {
width: 300,
backgroundColor: '#1c313a',
borderRadius: 25,
marginVertical: 20,
paddingVertical: 12
},
buttonText: {
fontSize: 16,
fontWeight: '500',
color: '#ffffff',
textAlign: 'center'
}
});
And my Drawer File
i.e LandingScreen.js
/**
* Sample React Native App
* https://github.com/facebook/react-native
*
* #format
* #flow strict-local
*/
import React from 'react';
// import { Router, Stack, Scene } from 'react-native-router-flux';
import 'react-native-gesture-handler';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
import { createDrawerNavigator } from '#react-navigation/drawer';
import WorkProcessor from './workprocessor';
import OperationAnalytics from './OperationAnalytics';
import { Button, View, Text, TouchableOpacity, Image } from 'react-native';
const Stack = createStackNavigator();
const Drawer = createDrawerNavigator();
const NavigationDrawerStructure = (props) => {
//Structure for the navigatin Drawer
const toggleDrawer = () => {
//Props to open/close the drawer
props.navigationProps.toggleDrawer();
};
return (
<View style={{ flexDirection: 'row' }}>
<TouchableOpacity onPress={() => toggleDrawer()}>
{/*Donute Button Image */}
<Image
source={{ uri: 'https://raw.githubusercontent.com/AboutReact/sampleresource/master/drawerWhite.png' }}
style={{ width: 25, height: 25, marginLeft: 5 }}
/>
</TouchableOpacity>
</View>
);
}
function firstScreenStack({ navigation }) {
return (
<Stack.Navigator initialRouteName="FirstPage">
<Stack.Screen
name="FirstPage"
component={WorkProcessor}
options={{
title: 'Work-Processor', //Set Header Title
headerLeft: () => <NavigationDrawerStructure navigationProps={navigation} />,
headerStyle: {
backgroundColor: '#f4511e', //Set Header color
},
headerTintColor: '#fff', //Set Header text color
headerTitleStyle: {
fontWeight: 'bold', //Set Header text style
},
}}
/>
</Stack.Navigator>
);
}
function secondScreenStack({ navigation }) {
return (
<Stack.Navigator
initialRouteName="SecondPage"
screenOptions={{
headerLeft: () => <NavigationDrawerStructure navigationProps={navigation} />,
headerStyle: {
backgroundColor: '#f4511e', //Set Header color
},
headerTintColor: '#fff', //Set Header text color
headerTitleStyle: {
fontWeight: 'bold', //Set Header text style
}
}}>
<Stack.Screen
name="SecondPage"
component={OperationAnalytics}
options={{
title: 'Operational Analytics', //Set Header Title
}} />
</Stack.Navigator>
);
}
const LandingScreen = () => (
<NavigationContainer>
<Drawer.Navigator
drawerContentOptions={{
activeTintColor: '#e91e63',
itemStyle: { marginVertical: 5 },
}}>
<Drawer.Screen
name="FirstPage"
options={{ drawerLabel: 'Work-Processor' }}
component={firstScreenStack} />
<Drawer.Screen
name="SecondPage"
options={{ drawerLabel: 'Operation-Analytics' }}
component={secondScreenStack} />
</Drawer.Navigator>
</NavigationContainer>
);
export default LandingScreen;
When i am clicking on login button i.e loginMove .. it is not moving to navigation drawer screen and giving error: -
Error: Looks like you have nested a 'NavigationContainer' inside another. Normally you need only one container at the root of the app, so this was probably an error. If this was intentional, pass 'independent={true}' explicitely. Note that this will make the child navigators disconnected from the parent and you won't be able to navigate between them.
Please can some one help me completing this flow. I am ready for doing any code changes it's my PoC
You cannot embedd NavigationContainer, only stacks, drawers, tabs, etc
I suggest you to make two Navigations, one for login, one logged. This prevent to back to login screen when already logged in.
Example
// App.js
return(
<NavigationContainer>
{isLogged ? <LoggedNav /> : <LoginNav />}
</NavigationContainer>
)
With your Drawer in LoggedNav and Stacks in LoginNav
OR
In a first stack, you have a screen with your drawer stack and one with your landing page stack. You can embedd stacks as much as you want but not NavigationContainer. A screen can be a stack without problems.
function Login({ navigation }) {
return (
<Stack.Navigator initialRouteName="FirstPage">
<Stack.Screen
name="FirstPage"
component={WorkProcessor}
options={{
title: 'Work-Processor', //Set Header Title
headerLeft: () => <NavigationDrawerStructure navigationProps={navigation} />,
headerStyle: {
backgroundColor: '#f4511e', //Set Header color
},
headerTintColor: '#fff', //Set Header text color
headerTitleStyle: {
fontWeight: 'bold', //Set Header text style
},
}}
/>
</Stack.Navigator>
);
}
const LandingScreen = () => (
<Drawer.Navigator
drawerContentOptions={{
activeTintColor: '#e91e63',
itemStyle: { marginVertical: 5 },
}}>
<Drawer.Screen
name="FirstPage"
options={{ drawerLabel: 'Work-Processor' }}
component={firstScreenStack} />
<Drawer.Screen
name="SecondPage"
options={{ drawerLabel: 'Operation-Analytics' }}
component={secondScreenStack} />
</Drawer.Navigator>
);
return(
<NavigationContainer>
<Stack.Navigator initialRouteName="login">
<Stack.Screen name="login" component={Login} ... />
<Stack.Screen name="landing" component={LandingScreen} ... />
</Stack.Navigator>
</NavigationContainer>
)
I have a small app which should have a drawer menu in the side
and a small Plus button which slides up a panel with more 4 buttons
something like this:
the app.js initiate a Switch navigator that have 2 screens, one for login and one for a Stack
the stack has the DrawerNavigation as the menu screen and other screens also.
and in the Drawer navigation there's some other screens:
the code below:
const SideMenuDrawer = createDrawerNavigator({
Main: MainScreen,
'Invite A Friend Screen': InviteAFriendScreen,
About: AboutScreen,
Schedule: ScheduleScreen,
Groups: GroupsScreen
},
{
navigationOptions: ({ navigation }) => {
const { routeName } = navigation.state.routes[navigation.state.index];
return {
headerTitle: routeName,
headerTintColor: '#ffffff',
headerStyle: {
backgroundColor: '#2F95D6',
borderBottomColor: '#ffffff',
borderBottomWidth: 3,
},
headerTitleStyle: {
fontSize: 18
}
}
}
}
);
const AppStack = createStackNavigator({
MainScreen: SideMenuDrawer,
PhotoScreen: PhotoScreen,
DocumentScreen: DocumentScreen,
AudioScreen: AudioScreen,
GalleryScreen: GalleryScreen
},
{
defaultNavigationOptions: ({ navigation }) => {
return {
headerLeft: (
<Icon
name="md-menu"
size={35}
style={{ paddingLeft: 10 }}
color="white"
onPress={() => navigation.openDrawer()}
/>
)
}
}
}
);
const AppContainer = createAppContainer(createSwitchNavigator(
{
LoginSplashScreen: LoginSplashScreen,
MainScreen: AppStack
},
{
initialRouteName: 'MainScreen',
}
));
export default class App extends React.Component {
render() {
return (
<AppContainer />
)
}
}
and the SlidingPanel is in the render() function of the Menu screen:
class MainScreen extends React.Component {
state = {
slideUpPanelvisible: false
}
render() {
const window = Dimensions.get('window');
const { navigation } = this.props;
const signedIn = global.signedIn;
const name = global.name;
const photoUrl = global.photoUrl;
return (
<View style={{ flex: 1 }}>
<View style={[styles.container]} >
<Text style={styles.header}>Welcome {name}</Text>
<Image style={styles.image} source={{ uri: photoUrl }} />
</View>
<View style={styles.addButton}>
<TouchableOpacity
onPress={() => this.setState({ slideUpPanelvisible: true })} >
<Icon name="add-circle" size={60} color='#0E2E49' />
</TouchableOpacity>
</View>
<SlidingUpPanel
visible={this.state.slideUpPanelvisible}
startCollapsed={true}
draggableRange={{ top: window.height * 0.4, bottom: 0 }}
onRequestClose={() => this.setState({ slideUpPanelvisible: false })}
allowDragging={true}
>
<View style={styles.panelcontainer}>
<Text style={styles.header}>Text inside the Sliding Panel </Text>
</View>
</SlidingUpPanel>
</View>
)
}
}
but the drawer doesnt show on android device (GEnymotion, android studio and a real device)
on an Iphone device it works great!
what am i doing wrong?
In latest versions of react-navigation, you need to add react-native-gesture-handler and link it. Otherwise gestures will not work on Android.
https://github.com/kmagiera/react-native-gesture-handler
npm install --save react-native-gesture-handler
react-native link react-native-gesture-handler
Also make sure things are linked properly(Sometimes auto-linking can fail). After this you can see that drawer is working in android.
Refer Documentation: https://kmagiera.github.io/react-native-gesture-handler/docs/getting-started.html
I'm using a TabNavigator nested inside DrawerNavigator.
My TabNavigator contains 2 screens and DrawerNavigator has 4 routes, one of which is the TabNavigator.
When I swipe to second tab inside my TabNavigator, then use the drawer to go to some other route and use the drawer to come back to TabNavigator, it is an error.
Here is the TabNavigator:
const MyTabNavigator = TabNavigator(
{
Tab1: {
screen: StackNavigator1,
navigationOptions: ({ navigation }) => ({
tabBarLabel: "Tab1"
})
},
Tab2: {
screen: StackNavigator2,
navigationOptions: ({ navigation }) => ({
tabBarLabel: "Tab2",
header: false
})
}
},
{
tabBarPosition: 'top',
tabBarOptions: {
activeTintColor: '#000000',
inactiveTintColor: '#707070',
labelStyle: labelStyle,
style: {
backgroundColor: '#ffffff',
},
indicatorStyle: {
borderBottomColor: '#ff3278',
borderBottomWidth: 3
}
}
});
And here is the DrawerNavigator:
const MyDrawerNavigator = DrawerNavigator(
{
Tabs: {
screen: MyTabNavigator
},
Key1: {
screen: Navigator1
}
.
.
.
},
{
contentComponent: (props) => {
return <View>
<View style={styles.drawerHeaderStyle}>
<Text style={styles.drawerHeaderTextStyle}>{`Welcome user`}</Text>
</View>
<DrawerItems {...props} />
<View style={styles.emptySpace} />
<Touchable
onPress={() => {
// Logout User
}}
style={styles.logoutButton}
background={Touchable.Ripple('grey')}>
<Text style={styles.buttonFont}>{"Logout"}</Text>
</Touchable>
</View>
}
});
Each of the StackNavigators have 2 screens. Something like:
const StackNavigator1 = StackNavigator(
{
Screen1: {
screen: Screen1,
navigationOptions: ({ navigation }) => ({
header: false
})
},
Screen2: {
screen: Screen2,
navigationOptions: ({ navigation }) => ({
header: false,
tabBarVisible: false,
swipeEnabled: false,
drawerLockMode: 'locked-closed'
}),
}
}, {
headerMode: "screen"
});
So when I swipe to "Key1" then use drawer to come to Navigator1 and finally use drawer to go back to "Tabs", I get an error saying
Error: There is no route defined for key Screen1, Must be one of Screen3, Screen4.
Where Screen3 and Screen4 reside inside StackNavigator2.
I hope I was able to describe the issue appropriately. Any ideas?
Alright. I've figured out a solution. It's a little hard to explain but I'll try nonetheless.
To get it to work I had to overwrite the onItemPress method of the DrawerItems myself.
My DrawerNavigation now looks like this:
const MyDrawerNavigator = DrawerNavigator(
{
Tabs: {
screen: MyTabNavigator
},
Key1: {
screen: Navigator1
}
.
.
.
},
{
contentComponent: (props) => {
return <View>
<View style={styles.drawerHeaderStyle}>
<Text style={styles.drawerHeaderTextStyle}>{`Welcome user`}</Text>
</View>
<DrawerItems {...props} onItemPress={(routeOptions) => {
props.navigation.navigate(routeOptions.route.routes[routeOptions.route.index].routeName, {})
}} />
<View style={styles.emptySpace} />
<Touchable
onPress={() => {
// Logout User
}}
style={styles.logoutButton}
background={Touchable.Ripple('grey')}>
<Text style={styles.buttonFont}>{"Logout"}</Text>
</Touchable>
</View>
}
});
Notice the onItemPress added in DrawerItems. This rather looks like a bug in react-navigation itself.
I had been facing these problems too but I came up with a solution building up my own header that will call drawer navigator.
class Header extends Component {
render() {
return (
<View>
<Logo />
<TouchableOpacity onPress={() => this.props.navigation.navigate('DrawerOpen')}>
<Icon size={24} style={{ color: '#fff' }} name="navicon" />
</TouchableOpacity>
</View>
)
}
}
Header.propTypes = {
navigation: PropTypes.instanceOf(Object).isRequired,
}
export default withNavigation(Header)
Wrapping your screens with withNavigation() maybe will do the trick.
I'm building an Android app with React Native.
How can you force a TextInput to "unFocus", meaning the cursor is blinking inside the text field. There are functions for isFocused() and onFocus(), but how do I actually get the text field to give up focus. You would think it does so automatically once I hit enter, but that's not the case.
import React, {Component} from 'react';
import { AppRegistry, Text, View, StyleSheet, TextInput, TouchableOpacity}
from 'react-native';
var SHA256 = require("crypto-js/sha256");
export default class LoginForm extends Component{
constructor(props){
super(props);
this.state = {
email: '',
password:''
};
}
tryLogin = () => {
if(this.state.email=="email123" && this.state.password == "password"){
console.log("password verified");
this.props.navigator.replace({
title: 'Dashboard'
});
}
console.log(this.state.email);
console.log(this.state.password);
console.log("Hash" + SHA256(this.state.password));
}
render(){
return(
<View style={styles.container}>
<TextInput
style={styles.input}
placeholder="Email address"
placeholderTextColor="white"
onChangeText={(email) => this.setState({email})}>
</TextInput>
<TextInput style={styles.input}
placeholder="Password"
placeholderTextColor="white"
secureTextEntry
onChangeText={(password) => this.setState({password})}>
</TextInput>
<TouchableOpacity style={styles.loginButtonContainer} onPress={this.tryLogin}>
<Text style={styles.loginButtonText}>LOGIN</Text>
</TouchableOpacity>
</View>
);
}
}
AppRegistry.registerComponent('LoginForm', () => LoginForm);
const styles = StyleSheet.create({
container: {
padding: 20
},
input:{
height: 40,
backgroundColor: '#e74c3c',
marginBottom: 20,
color: 'white',
paddingHorizontal: 15,
opacity: .9
},
loginButtonContainer:{
justifyContent: 'center',
backgroundColor: '#bc4c3c',
paddingVertical:15
},
loginButtonText:{
textAlign:'center',
color:'white',
fontWeight: '700',
fontSize: 24
}
})
This probably won't matter as much for real users but I'm just emulating and its pesky if I want to reload.
A better way is to use ScrollView and Keyboard.dismiss. By using ScrollView when the user taps outside of textInput, keyboard dismissed. It's done because ScrollView default property for keyboardShouldPersistTaps is never. It's the behavior the user expects. For dismiss the keyboard, or it's equivalent blur the textInput, when the user tap on the login button add Keyboard.dismissed() to the tryLogin function.
import React, {Component} from 'react';
import { AppRegistry, Text, View, StyleSheet, TextInput, TouchableOpacity, ScrollView, Keyboard}
from 'react-native';
var SHA256 = require("crypto-js/sha256");
export default class LoginForm extends Component{
constructor(props){
super(props);
this.state = {
email: '',
password:''
};
}
tryLogin = () => {
Keyboard.dismiss();
if(this.state.email=="email123" && this.state.password == "password"){
console.log("password verified");
this.props.navigator.replace({
title: 'Dashboard'
});
}
console.log(this.state.email);
console.log(this.state.password);
console.log("Hash" + SHA256(this.state.password));
}
render(){
return(
<ScrollView style={styles.container}>
<TextInput
style={styles.input}
placeholder="Email address"
placeholderTextColor="white"
onChangeText={(email) => this.setState({email})}>
</TextInput>
<TextInput style={styles.input}
placeholder="Password"
placeholderTextColor="white"
secureTextEntry
onChangeText={(password) => this.setState({password})}>
</TextInput>
<TouchableOpacity style={styles.loginButtonContainer} onPress={this.tryLogin}>
<Text style={styles.loginButtonText}>LOGIN</Text>
</TouchableOpacity>
</ScrollView>
);
}
}
AppRegistry.registerComponent('LoginForm', () => LoginForm);
const styles = StyleSheet.create({
container: {
padding: 20
},
input:{
height: 40,
backgroundColor: '#e74c3c',
marginBottom: 20,
color: 'white',
paddingHorizontal: 15,
opacity: .9
},
loginButtonContainer:{
justifyContent: 'center',
backgroundColor: '#bc4c3c',
paddingVertical:15
},
loginButtonText:{
textAlign:'center',
color:'white',
fontWeight: '700',
fontSize: 24
}
})
You can use Keyboard API.
import { Keyboard, TextInput } from 'react-native';
<TextInput
onSubmitEditing={Keyboard.dismiss}
/>
Please see the full example in react native offical document.
I managed to solve this with this.ref reference.
First, you assign to the TextInput a ref, like this:
<input ref="myInput" />
Then, you call the blur() method to this.refs.myInput from a function
blurTextInput(){
this.refs.myInput.blur()
}
My use case was a little different. The user wouldn't enter a value directly in the input field. The field was mainly used to capture the user's attempt at entering a value and open a modal instead. I wanted to blur the field after the modal closed to reduce the extra tap the user would have to do later.
If using Hooks, you can do something as simple as
const inputRef = useRef(null);
<Input
ref={inputRef}
{...props}
/>
Then just call this anywhere you need it.
inputRef.current.blur();
Found it actually.It doesn't look as pretty and my intuition says this isn't a very "react" solution but if you want it here it is.
<TextInput
style={styles.input}
ref="email_input"
onSubmitEditing={() => this.refs['email_input'].blur()}
placeholder="Email address"
placeholderTextColor="white"
onChangeText={(email) => this.setState({email})}/>
Noah's answer above works well, but using string refs is now discouraged in React, and is likely going to be deprecated soon. Instead, you should use a callback function that gets called when the component you want to reference renders.
<TextInput
ref={(c: any) => {
this.textInputRef = c;
}}
onSubmitEditing={() => this.textInputRef.blur()}
/>
If you're using Flow, you can then specify the type of your ref by placing something like this outside of your render function:
textInputRef: ?TextInput;
If you want to lose focus after submiting, use blurOnSubmit property.
<TextInput
blurOnSubmit={true}
//other props
/>
It does what it needs
function TextInputCustom({ placeholder, style }) {
React.useEffect(() => {
const keyboardHide = Keyboard.addListener('keyboardDidHide', () => {
Keyboard.dismiss();
});
return () => {
keyboardHide.remove()
}
}, []);
return (
<TextInput
style={style}
placeholder={placeholder}
/>
)
}
export default TextInputCustom;
I used the below code and it worked perfect for me:
i wrap all the view inside TouchableWithoutFeedback and
onPress={() => {Keyboard.dismiss();}}
import {View,TouchableWithoutFeedback,Keyboard,} from 'react-native';
......
<SafeAreaView>
<ScrollView nestedScrollEnabled={true}>
<TouchableWithoutFeedback
onPress={() => {Keyboard.dismiss();}}>
<View style={styles.container}>
{/* ..... */}
</View>
</TouchableWithoutFeedback>
</ScrollView>
</SafeAreaView>