TextInput loses focus after every keystroke react-native - react-native

I have the following code (full example):
import React, { useState, useEffect } from 'react';
import { SafeAreaView, View, TextInput, Button, StyleSheet } from 'react-native';
const App = () => {
const [textblocks, setTextblocks] = useState([]);
const CreateTextBlockHandler = () => {
let array = [...textblocks];
array.push({text: ''});
setTextblocks(array);
};
const SaveTextHandler = (index, text) => {
let array = [...textblocks];
array[index].text = text;
setTextblocks(array);
};
const RenderTextInputs = () => {
return textblocks.map((item, index) => {
return (
<View key={index}>
<TextInput style={styles.textinput} placeholder="text" value={textblocks[index].text} onChangeText={value => SaveTextHandler(index, value)} />
</View>
);
});
};
return (
<SafeAreaView style={styles.pancontainer}>
<RenderTextInputs />
<Button title="Create textblock" onPress={CreateTextBlockHandler} />
</SafeAreaView>
);
};
const styles = StyleSheet.create({
pancontainer: {
flex: 1,
alignItems: 'center',
justifyContent: 'center'
},
textinput: {
width: 200,
margin: 10,
borderWidth: 1,
borderColor: 'black'
}
});
export default App;
How it works: I have a button to dynamically add a new textinput. This works. The problem is, for every character I enter in a textput, the focus is lost after every character.
I created a snack, you can test it here: https://snack.expo.io/BJcHxluyI.
I THINK I need to save the reference to the textinput somewhere, and then give the focus back to the textinput after every keystroke, but I don't know how to do that.

Change
return (
<SafeAreaView style={styles.pancontainer}>
<RenderTextInputs />
<Button title="Create textblock" onPress={CreateTextBlockHandler} />
</SafeAreaView>
);
To
return (
<SafeAreaView style={styles.pancontainer}>
{RenderTextInputs()}
<Button title="Create textblock" onPress={CreateTextBlockHandler} />
</SafeAreaView>
);
Or put RenderTextInputs outside App and pass data via props. With first syntax react treats RenderTextInputs as a component and, as it is nested in App, mounts it again on each App render.

Related

Show or Hide element or Style element by using ref or nativeID

How can I use the refText to update the element 'Text'
const refText = null;
const doSomething = () =>{
refText.changeVisibility("hidden"); // something like that
}
return <Text ref={refText} onPress={doSomething}>Some Text</Text>;
I tried to find any way to work with it, but can't find any solution over google. Or maybe I missed.
setNativeProps may be what you're looking for, however this is generally not the recommended way to make updates to an element. Instead, consider using state and updating relevant props/styles of your component in response to that state change:
Example on Expo Snack
import { useState } from 'react';
import { Text, View, StyleSheet, Button } from 'react-native';
export default function App() {
const [visible, setVisible] = useState(true);
return (
<View style={styles.container}>
<Button title="Toggle" onPress={() => setVisible(previous => !previous)} />
{visible && (
<Text onPress={() => setVisible(false)} style={{padding: 20}}>Click this text to hide it</Text>
)}
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
});

How does onBlur event work in react native? it doesn't work i want it to

I made an expo app.
I want to make an AutoCompleteInput.
When focusing and changing TextInput, It will render the same words.
When ListItem clicks, TextInput's value will update it and it doesn't render.
When TextInput focus out, ListItem doesn't render.
In my code, the onPress event works first. onPress event works after.
how can i do?
and how does work onBlur event?
i moved onBlur event other component, but it doesn't work...
// App.js
...
return (
<View style={styles.container}>
<View style={styles.contentContainer}>
<Text>my content</Text>
</View>
<AutoInput />
<StatusBar style="auto" />
</View>
);
// AutoInput.jsx
import { ListItem, TextInput } from '#react-native-material/core';
import { useCallback, useState } from 'react';
import { ScrollView, StyleSheet, View } from 'react-native';
import { locations } from '../../utils/constants';
const initialLocation = locations.map(({ name }) => name);
const AutoInput = () => {
const [location, setLocation] = useState('');
const [searchedLocations, setSearchedLocations] = useState([]);
const handleChangeInputText = useCallback(
(newString) => {
setLocation(newString);
if (!newString) {
setSearchedLocations(initialLocation);
return;
}
const filteredLocations = locations
.filter(({ name }) => name.includes(newString))
.map(({ name }) => name);
setSearchedLocations(filteredLocations);
},
[initialLocation]
);
return (
<View style={styles.container}>
<TextInput
placeholder="지역을 검색해주세요"
onBlur={() => {
console.log('blur');
setSearchedLocations([]);
}}
onFocus={() => console.log('focus')}
onChangeText={handleChangeInputText}
value={location}
/>
<ScrollView style={styles.scroll}>
{searchedLocations.map((searchLocation) => (
<ListItem
key={searchLocation}
title={searchLocation}
onPress={() => alert(searchLocation)}
style={styles.listItem}
/>
))}
</ScrollView>
</View>
);
};
const styles = StyleSheet.create({
container: { position: 'absolute', width: '100%' },
scroll: { maxHeight: 300 },
listItem: { width: '100%' },
});
export default AutoInput;
enter image description here

How do I make my code so that my initial input from text input does not get deleted

my code:
import { StyleSheet, Text, View, TextInput, SafeAreaView } from "react-native";
import { useState } from "react";
export default function App() {
const [name, setName] = useState("");
return (
<SafeAreaView>
<View style={styles.container}>
</View>
<TextInput
style={styles.input}
placeholder="John Doe"
onSubmitEditing={(value) => setName(value.nativeEvent.text)}
/>
<Text>Welcome: {name}</Text>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
input: {
borderColor: "gray",
width: "100%",
borderWidth: 1,
borderRadius: 10,
padding: 10,
},
});
when I press enter the value goes to {name}, but when I type in another input and press enter, the initial value gets deleted. I want to keep adding on instead of having the initial value deleted.
You need to add the text value into an array instead of a string
const [names, setNames] = useState([]);
to add to the array like this
<TextInput
style={styles.input}
placeholder="John Doe"
onSubmitEditing={(value) => {
setNames(previousVal => previousVal.concat([value.nativeEvent.text]))
}}
/>
and finally to display
{names.map((item,index) => (
<Text key={index}>Welcome: {item}</Text>
))}

React Native useState not auto Updating?

why useState auto update? I'll press button and not showing textinput. but I can save file without change. textinput will be showing. sorry my bad english
import React, { useState,useEffect } from 'react';
import {Text, TextInput, View, Button,} from 'react-native';
const Test = ({navigation}) => {
const [textInput, settextInput] = useState([]);
useEffect(() => {
addTextInput = (key) => {
textInput.push([<TextInput style={{backgroundColor :'#7ACB4A',marginTop:10}} key={key} />]);
settextInput(textInput);
console.log(textInput);
}
},[textInput]);
return(
<View>
<Button title='+' onPress={() =>
addTextInput(textInput.length)} />
{textInput.map((value, index) => {
return value
})}
<Text>{textInput.length}</Text>
</View>
);
}
export default Test;
I have a few suggests to make your code better.
Don't change state value if not in use 'setState'.
This is false by nature and causes errors.
addTextInput = (key) => {
textInput.push([<TextInput style={{backgroundColor :'#7ACB4A',marginTop:10}} key={key} />]);
settextInput(textInput);
console.log(textInput);
}
State merely contains value, it should not contain different things. You should return TextInput in your map function.
I try rewrite your code, sorry because my english. Hope help you
code:
const [textInput, setTextInput] = React.useState(['1', '2'])
const addTextInput = (key: string) => {
const tempInput = textInput.concat([key])
setTextInput(tempInput)
}
return (
<View style={{ alignItems: 'center', justifyContent: 'center', flex: 1 }}>
<Button title="+" onPress={() => addTextInput(textInput.length.toString())} />
{textInput.map((value, index) => {
return (
<TextInput style={{ backgroundColor: '#7ACB4A', marginTop: 10, width: '70%' }} key={index + ''} />
)
})}
<Text>{textInput.length}</Text>
</View>
)
}

React Native OnPress issue i have been having

I am new to react native and have been doing this for a week or so. I just finished the tutorials for making an interactive buttons and work on it. But i am stuck on this. The app is really simple right now, just trying to make a form and add some trigger event using onPress on it.
Below is the portion of my code. I am simply lost for words why its not calling SubmitThisForm() on the onPress event.
Can you guys help me on this.
Thanks a lot.
import React, { Component } from 'react';
import {Container, Content, InputGroup,Button, View, Icon, Card,
CardItem, Text, Body} from 'native-base';
import {Input} from './common';
class LoginForm extends Component {
state = {email: '', password: ''};
SubmitThisForm() {
console.log("Can you see this");
}
render () {
return (
<Container>
<Content>
<Card style={styles.FormContainer}>
<CardItem>
<Body>
<InputGroup borderType="regular">
<Icon name="ios-mail-outline" style={{color:'#384850'}}/>
<Input
placeHolder="example#example.com"
value = {this.state.email}
onChangeText={email=>this.setState( { email })}
/>
</InputGroup>
<InputGroup borderType="regular">
<Icon name="lock" style={{color:'#384850'}}/>
<Input
secureTextEntry= {true}
placeHolder="password"
value = {this.state.password}
onChangeText={password=>this.setState( { password })}
/>
</InputGroup>
</Body>
</CardItem>
</Card>
<View style={styles.SignIn}>
<Button block warning onPress={ () => {this.SubmitThisForm()}}><Text>Sign In</Text></Button>
</View>
<View style={styles.SignUp}>
<Button block info><Text>Sign Up</Text></Button>
</View>
<View style={styles.SignIn}>
<Button block primary><Text>Forgot Password</Text></Button>
</View>
</Content>
</Container>
);
};
}
const styles = {
ErrorTextStyle: {
fontSize: 20,
alignSelf: 'center',
color: 'red'
},
FormContainer:{
marginTop:30,
shadowColor:'#000',
shadowOffset:{width:0,height:2},
shadowOpacity:0.1,
shadowRadius:2,
},
SignIn:{
marginTop:10,
flex:1,
alignSelf:'stretch',
},
SignUp:{
marginTop:40,
flex:1,
alignSelf:'stretch',
}
}
export default LoginForm
The include input component is like this:
import React from 'react';
import {Text, View, TextInput} from 'react-native';
const Input = ({ label,value,onChangeText,placeHolder,secureTextEntry }) => {
const {InputStyle,LabelStyle,ContainerStyle } = styles;
return (
<View style = {ContainerStyle}>
<TextInput
secureTextEntry = {secureTextEntry}
placeholder={placeHolder}
autoCorrect={false}
style = {InputStyle}
value={value}
onChangeText={onChangeText}
/>
</View>
);
};
const styles = {
InputStyle:{
color:'#000',
paddingRight:5,
paddingLeft:5,
fontSize:18,
lineHeight:30,
flex:2,
height:40
},
LabelStyle:{
fontSize:18,
paddingLeft:20,
flex:1,
},
ContainerStyle:{
height:40,
flex:1,
flexDirection:'row',
alignItems:'center'
}
}
export { Input };
You need to either use an Arrow function, or bind() SubmitThisForm to your Component.
You can either declare your method like:
SubmitThisForm = () => {
console.log('Can you see this?')
}
Or, you can bind() your function in the constructor by adding:
constructor() {
super()
this.SubmitThisForm = this.SubmitThisForm.bind(this)
}
If you do not bind this in your custom functions, this will equal undefined. When you use Arrow functions however, this is lexically scoped which means the context of this will be the enclosing context (LoginForm)