Keyboard disappears on every key press in React Native - javascript

I want to map key value pairs in react native. The value being editable text entry. The mapped components show up fine, but when I try to edit the TextInput, the keyboard disappears when i type the first letter. Don't know whats causing the problem.
If i just put a TextInput in the parent element, it works absolutely fine but doesn't work when I use the map function.
<View style={styles.main}>
<View>
{this._getDetailElements()}
</View>
</View>
_getDetailElements() function
_getDetailElements = () => {
return Object.keys(this.state.data).map(elem => (
<View key={shortid.generate()} style={styles.element}>
<TextInput
editable={this.state.editable}
onChangeText={text => this.setState({seletedText: text})}
value={this.state.selectedText}
/>
</View>
)
);
}

i think you should just change the value to defaultValue Like this :
<TextInput
editable={this.state.editable}
onChangeText={text => this.setState({seletedText: text})}
defaultValue={this.state.selectedText}
/>
Good luck

It's because your key on the map changes everytime it rerenders.
Just use the index of the map iteration as key
_getDetailElements = () => {
return Object.keys(this.state.data).map((elem, index) => (
<View key={index} style={styles.element}>
<TextInput
editable={this.state.editable}
onChangeText={text => this.setState({seletedText: text})}
value={this.state.selectedText}
/>
</View>
)
);
}

Related

My State Does Change But Components Are Disappear When I Update My State In React Native How To Fıx This?

const DetailedSearchScreen=({ navigation })=> {
const mydefauthor='no';
const mydeftitle='data';
var [dataset, setDataset]=useState({data:[{Author:'Deneme', Title:'yapiyorum'}]});
return (
<ScrollView contentContainerStyle={styles.container}>
<TextInput onChangeText={text=>det_author=text} placeholder="Enter Author" style={styles.item_style} onClick={()=>{
console.log(dataset, "You are the hero!");
}}/>
<TextInput onChangeText={text=>det_keyword=text} placeholder="Enter Keyword" style={styles.item_style}/>
<TextInput onChangeText={text=>det_year=parseInt(text)} placeholder="Year" style={styles.item_style}/>
<TextInput onChangeText={text=>det_sub_date=text} placeholder="Enter Submission Date As Year-Month-Day" style={styles.item_style}/>
<TouchableOpacity onPress={()=>{
var data_=make_search();
console.log("Data info: ",dataset);
var item={};
item['data']=data_;
setDataset(Object.assign({...dataset, ...item}));
console.log(dataset, "Yine mi olmadı be");
}} style={styles.button}><Text>Search</Text></TouchableOpacity>
<View>
{
dataset['data'].map((item, key)=>{
console.log(item);
return(
<Text>{item['Author']}</Text>
);
})}
</View>
</ScrollView>
);
}
part of the code is like that, when I read from the console.log result, it shows that state is changed but my mapped components disappear when I updated the state
You didn't enter your key prop in the Text element. You should have
<Text key={key}> ... </Text>
Also here you are using the array index as a key and it might cause errors.
You should use something that is unique to that data and will not change (title or author if they are unique and immutable).
The best option would be to have a unique id.
https://reactjs.org/docs/lists-and-keys.html

Textinputs according to number of items in react native

I have dyna;ic number of items in an array, and i should create text inputs to chnage these items, so how can i do it please ? any ideas ? I don't know how to use flatlist with text inouts.and how to handle every input, because the number is dynamic I'm new to react.
You can create a component as item to render in the flatlist, and in the ItemComponent you can put anything,
Eg:
const ItemCard = ({...props}) => {
return (
<View>
<Image />
<TextInput />
</View>
)
}
Other component:
<FlatList renderItem={({item, index}) => <ItemCard />} />
nameofArray.map(
(arrayObject)=>
{
<TextInput
value={arrayObject.value}//here comes which value you want to disp
/>
}
)
If your data is large then you should consider flatlist

How to change the focus of text input when using custom text input

1.Here is my custom text input custom component i define props ref which i want to use in
parent component
export const InputField = ({
placeholder,
onChangeText,
placeholderTextColor,
showSecureIcon,
isSecure,
onPressIcon,
keyboardType,
returnKeyType,
maxLength,
secureIconColor,
handleUseCallBack,
ref,
value
}) => {
return (
<View style={styles.container}>
<TextInput
style={styles.input}
placeholder={placeholder}
onChangeText={onChangeText}
placeholderTextColor={placeholderTextColor}
autoCapitalize="none"
secureTextEntry={isSecure}
keyboardType={keyboardType}
returnKeyType={returnKeyType}
maxLength={maxLength}
value={value}
ref={ref}
/>
<View style={styles.iconContainer}>
{showSecureIcon ?
<TouchableOpacity
onPress={onPressIcon}
>
<Ionicons
name={isSecure ? "eye-off-sharp" : "eye-sharp"}
color={secureIconColor}
size={constants.vw(25)}
/>
</TouchableOpacity>
:
null
}
</View>
</View>
)
}
2-Now the part where i want to change my ref
in this field i create the text inputs field of password and confirm where i want to change
my focus
const passwordRef = useRef(null);
const confirmPasswordRef =
useRef(null);
const onSubmitEditing=()=>{
confirmPasswordRef.current.focus();
}
<View style={{ marginTop: constants.vh(66) }}>
<Components.InputField
placeholder={constants.ConstStrings.setANewPassword}
ref={passwordRef}
onSubmitEditing={()=>onSubmitEditing()}
onChangeText={(text) => setState({
...state,
password: text
})}
/>
</View>
<View style={{ marginTop: constants.vh(20) }}>
<Components.InputField
ref={confirmPasswordRef}
placeholder={constants.ConstStrings.confirmPassword}
onChangeText={(text) => setState({
...state,
confirm_password: text
})}
/>
</View>
This part is the end part qwertyuiopsdf;';dsyuiopoiuteweryuiopuytreep[gfjklvcvbnm,mvcxzxcewqwe[poiuyd
The problem with your code is that you've created a custom input component, but haven't given to it the instructions on how to handle different methods.
So, in your case, the generic Input component knows what method is focus, but your custom one doesn't.
What you should do:
Make your input component a forwardRef one so that you can pass a ref to it and then be able to do actions on it.
Use useImperativeHandle so that you can call internal methods of your ref.
Create a focus fn which in your custom input will basically call the focus method of your ref.
You cannot pass the ref in props as you are doing, that just doesn't work in React.
I suppose all of your components are functional, in that case:
export const InputField = React.forwardRef({
placeholder,
...
}, ref) => { // pass a ref to here, this way you will let React know to associate the ref from external component to an internal ref
const textInput = useRef(null); // Create a ref to pass to your input
useImperativeHandle(ref, () => ({ // To be able to call `focus` from outside using ref
focus,
});
const focus = textInput.current.focus();
return (
<View style={styles.container}>
<TextInput
ref={textInput}
style={styles.input}
...
/>
...
</View>
)
}
And then in your component you just have to pass a fresh ref created by useRef and then you'll be able to call focus on in.
Tell me whether that solves it for you!

How to pass data from Class to function in React Native array, firebase, stack navigator v5

Hay I am struggling on how to pass data that's in a class, to another react native component. I am able to display data on the same screen, however I want to have the user input some text and have it display on another screen.
1) Initial Screen: User presses button to navigate to text inputs, and will navigate back to this screen to view the list. Note: If I add the list here I get an error "undefined is not an object". Because I was not able to figure out how to PASS THE LISTARRAY variable to that screen.
export const GoalsScreen = ({ navigation }) => {
return (
<SafeAreaView style={styles.container}>
<Header>
{/* header title */}
<Text style={styles.goalText}> Expand your life</Text>
{/* add goal button goto stack */}
<TouchableOpacity onPress={() => navigation.navigate("AddGoal")} >
<Text style={styles.addBtn}> + </Text>
</TouchableOpacity>
</Header>
{/* Error here, need to get data from other screen */}
<FlatList
data={this.state.listArray}
renderItem={({ item, index }) => {
return (
<View>
<Text style={{ fontSize: 30 }}>{item.fireListGoal} </Text>
<Text style={{ fontSize: 20 }}>{item.fireListCat}</Text>
<Text style={{ fontSize: 15 }}> {item.fireListWhy}</Text>
</View>
);
}}
>
</FlatList>
</SafeAreaView>
);
}
2) List Screen: If I put the flatList here everything works, but I need to PASS THE DATA thats inputted here in the firebase real-time database and display it on the other screen shown above.
export class AddGoalList extends React.Component {
// state and defult values
constructor(props) {
super(props)
// set inital values
this.state = {
listArray: [],
goal: '',
category: 'Pick One',
why: '',
}
}
//triggers rerendering, put values in a JSON array
componentDidMount() {
goalsRef.on('value', (childSnapshot) => {
const listArray = [];
childSnapshot.forEach((doc) => {
listArray.push({
key: doc.key,
fireListGoal: doc.toJSON().fireListGoal,
fireListCat: doc.toJSON().fireListCat,
fireListWhy: doc.toJSON().fireListWhy
});
this.setState({
listArray: listArray.sort((a, b) => {
return (
a.fireListGoal < b.fireListGoal,
a.fireListCat < b.fireListCat,
a.fireListWhy < b.fireListWhy
);
}),
});
});
});
}
// when button pressed...
onGoal = ({ }) => {
// if form empty alert user
if (this.state.goal.trim() && this.state.why.trim() === '') {
alert("Please fill form.");
return;
}
if (this.state.category.valueOf() === 'Pick One') {
alert("Fill in all inputs.");
return;
}
// otherwise push data to firebase
goalsRef.push({
fireListGoal: this.state.goal,
fireListCat: this.state.category,
fireListWhy: this.state.why
});
}
render() {
return (
// KeyboardAvoidingView ==> prevent keyboard from overlapping
<KeyboardAvoidingView style={styles.container}>
<SafeAreaView>
<Text>Sparks your life!</Text>
{/* Goal title */}
<Text>What is your goal</Text>
<TextInput
placeholder="Enter your goal"
keyboardType='default'
onChangeText={
(text) => {
this.setState({ goal: text });
}
}
value={this.state.goal}
/>
{/* pick selected cetegory */}
<Text>Pick a Category</Text>
{/* picker component */}
<Picker
selectedValue={this.state.category}
onValueChange={(itemValue) => this.setState({ category: itemValue })}
>
<Picker.Item label="Pick One" value="Pick One" />
<Picker.Item label="Fitness" value="Fitness" />
<Picker.Item label="Health" value="Health" />
<Picker.Item label="Travel" value="Travel" />
<Picker.Item label="Wealth" value="Wealth" />
<Picker.Item label="Creativity" value="Creativity" />
<Picker.Item label="Skills" value="Skills" />
</Picker>
<Text>Why did you pick this goal?</Text>
<TextInput
placeholder="Enter your why"
keyboardType='default'
onChangeText={
(text) => {
this.setState({ why: text });
}
}
value={this.state.why}
/>
{/* nav back to My Goal list */}
<Button title="add goal" onPress={this.onGoal.bind(this)} />
</SafeAreaView>
{/* remove list here and add to other GoalsScreen */}
<FlatList
data={this.state.listArray}
renderItem={({ item, index }) => {
return (
<View>
<Text style={{fontSize: 30}}>{item.fireListGoal} </Text>
<Text style={{fontSize: 20}}>{item.fireListCat}</Text>
<Text style={{fontSize: 15}}> {item.fireListWhy}</Text>
</View>
);
}}
>
</FlatList>
</KeyboardAvoidingView>
);
}
}
I have tried to useState and pass data as a param but got errors, in able to use the variable navigation in a class..? Also tried to put it in a separate function and that did now work ether. I'll add my code bellow so you can take a look. Any suggestions and or references to any helpful docs would really be appreciated.
Would really appreciate some help, been trying to resolve this for the past few days with no luck. Many thanks!
If i understand the flow correctly, what you want is the following:
Initially, you have a first screen with a list of items (GoalsScreen). From there the user can open a new screen, where he can add items (AddGoalScreen). So, when the user goes back, you want him to see the updated list.
First of all, in the above code, the GoalsSrceen has not defined any state listArray, so that's why you get undefined error. You need to declare it just like you did in AddGoalScreen. Also, as i can see, the AddGoalScreen will no longer display this listArray, so you can simply move the goalsRef.on('value', ... subscription in the GoalsScreen. Doing so, each time you push to the firebase through AddGoalScreen, the on('value') subscription will be triggered inside GoalsScreen, and the GoalsScreen will rerender, keeping its state available. So you have your problem fixed

Tabbing through next text input not working

I want to pass focus to next text input on press of buttons.Everything was working fine till when I created customTextInput in another class and calling it through props.But now problem is focus is not changing on button press and I think it is related to some scope problem .Maybe it is not accessing this of other class(child component).
Following is the stuff I had done:
This is Custom Text input I had created in other js file
<View>
<CustomTextInput
textLogo={logo}
placeholder={placeholder}
value={value}
onChangeText={onTextChange}
isMultiline={isMultiline}
onFocus={() =>
{
this.setState({index:index,isFocused:true})
this.refs.scrollView.scrollTo({ x: 0, y: position, animated: true })}
}
ref={input =>(this[arrTextInput[index]] = input)}/>
</View>
This is function for changing the focus
customFocusNavigator = () => {
return(
<View style={styles.FocusNavigator}>
<TouchableOpacity onPress={() => {this[arrTextInput[this.state.index - 1]].focus()}} style={styles.bottomSubView}>
<Text>Previous</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() =>{this[arrTextInput[this.state.index + 1]].focus()}} style={styles.bottomSubView}>
<Text>Next</Text>
</TouchableOpacity>
</View>
)
}
And I am changing index of textInput on focus .
I hope I gave sufficient matter for my problem.Any help will be appreciated.Thank you
You dont need a function to change the focus, you can simply do it using onSubmitEditing
For example with 3 inputs you could do it like this:
<Input
placeHolder="Input1"
ref={input => (this.Input1 = input)}
onSubmitEditing={() => {this.Input2.focus(); }}
/>
<Input
placeHolder="Input2"
ref={input => (this.Input2 = input)}
onSubmitEditing={() => {this.Input3.focus(); }}
/>
<Input
placeHolder="Input3"
ref={input => (this.Input3 = input)}
onSubmitEditing={() => **GO SOMEWHERE ELSE** }}
/>
You set the ref on the later input and then pass the focus() on the previous one

Categories

Resources