How to update useState into TextInput - react-native

I have a simple <TextInput> in React Native and i want to print some text when value change. Its working after second character entered, but not, when user press just one char.
I try using functions and even with onChange and take from e.target.value but allways are missing one character at "search" state.
import React, { useState } from 'react';
import { TextInput, View, Text } from 'react-native';
const App = () => {
const [search, setSearch] = useState('');
const [searching, setSearching] = useState(false);
return(
<View>
<TextInput
onChangeText={(value) => {
setSearch(value)
setSearching(search=='' ? false : true)
}}
value = { search }
/>
{
searching ?
(
<Text>Searching</Text>
) : (
<Text>No searching</Text>
)
}
</View>
);
}
export default App
I expect to show "Searching" when TextBox value are not empty.

useState or setState may be asynchronous, so the first time you call setSearch(value), the search state may not be updated yet.
onChangeText={(value) => {
setSearch(value)
setSearching(search == '' ? false : true) // "search" is still previous value
}}
Instead, you can directly use value instead for checking.
onChangeText={(value) => {
setSearch(value)
setSearching(value == '' ? false : true) // value is latest
}}

You need to compare the actual value of the TextInput
Using search=='' ? false : true will check the previous state and won't change
onChangeText={(value) => {
setSearch(value)
setSearching(search=='' ? false : true)
}}
This will check for the changed value.
onChangeText={(value) => {
setSearch(value)
setSearching(value == '' ? false : true) // use value
}}
You need to use value instead of search
Just change this
setSearching(search=='' ? false : true)
to
setSearching(value=='' ? false : true)

After help of both i resolved. This is the code if help to somebody. The idea are a TextInput with a len icon on the left, and when user start to write made the call to Firebase and show a loading icon on the right (spinner).
<Icon
name='search'
size={25}
color={PRIMARY_BACKGROUND_COLOR}
style={styles.searchIcon}
/>
<TextInput
underlineColorAndroid = 'transparent'
style = { styles.textBox }
onChangeText={(value) => { onChangeText(value) }}
value = { search }
placeholder = { i18n.t('Search') }
/>
{
searching ?
(
<TouchableOpacity style = { styles.visibilityBtn }>
<Animatable.View
ref={ref => (this.AnimationRef = ref)}
animation='rotate'
easing='linear'
iterationCount='infinite'
>
<Icon
name='spinner-3'
size={20}
color={PRIMARY_BACKGROUND_COLOR}
/>
</Animatable.View>
</TouchableOpacity>
) : (
<TouchableOpacity onPress={ clearSearch } style = { styles.visibilityBtn }>
<Icon
name='close'
size={20}
color={PRIMARY_BACKGROUND_COLOR}
/>
</TouchableOpacity>
)
}
And the function
const onChangeText = value => {
setSearch(value)
setSearching(value =='' ? false : true)
Helper.getCategoriesSearch(value, (categories) => {
setSearching(false)
//props.searchResults(categories); THIS DO NOT WORK RETURN DATA TO props :(
})
}
Thanks All

Related

My if statement is not working in React Native

I want to build a search bar that filters a flatlist in react native. I'm doing so with a TextInput and a component SearchFilter.
In my homescreen I have this TextInput:
<TextInput
value={input}
onChangeText={(text) => setInput(text)}
style={{ fontSize: 16, marginLeft: 10 }}
placeholder="Search"
/>
And this component:
<SearchFilter data={Cars} input={input} setInput={setInput} />
In the component file I have my flatlist:
const searchFilter = (data, input, setInput) => {
console.log(input)
return (
<View>
<Text>SearchFilter</Text>
<FlatList
style={styles.list}
data={data}
renderItem={({ item }) => {
if (input === "") {
return (
<View>
<Text>test</Text>
</View>
)
}
}}
></FlatList>
</View>
);
};
When nothing is being searched I want test to be displayed.
The problem is that it shows nothing.
When I do a console.log(input) in my homescreen the console returns an emty string
but when I do a console.log(input) in my component file it returns {}. I do not know why. When I tried
if (input === " {}") {
return (
<View>
<Text>test</Text>
</View>
)
}
it also did not work.
Any asolutions?
I suppose the searchFilter is your component ?
If it is the case then you don't use the props correctly, try like this :
const SearchFilter = ({data, input, setInput}) => { ... rest of your code ... }
You can't compare a object like this, it's not the same (in the memory).
Assuming var x = {}
x == {} // false (it's the same 'content' but it's not saved at the same place in the memory
x == "{}" // false (x is a object "{}" is a string)`
Assuming var y = x
y == x // true
To compare basic object, you can use JSON.stringify() function, it's parse object to string like this : (JSON.stringify(x) == JSON.stringify({})) === true
It's explain why your condition doesn't work but I don't know why do you have a object as output (I'm not a react developer ^^)
I hope it's even be usefull for you

Is there a way to set a state with textinput when onChangeText is already in use?

Im trying to set a state with the values from a textinput (which is a reusable component), Im using onChangeText to setFieldValue (useFormikContext()), I also want to set a state which will be sending to the Parent component. I tried using onChange but noticed it saves the text without the last word/number, for instance if I type 0123456789, the setFieldValue gets 0123456789, but the other one (with onChange) gets only 012345678 (without 9).
Here is the code:
function AppFormField({ name, width, childToParent, ...otherProps }) {
const { setFieldTouched, setFieldValue, errors, touched, values } =
useFormikContext();
return (
<>
<TextInput
onBlur={() => setFieldTouched(name)}
onChangeText={(text) => setFieldValue(name, text)}
onChange={() => childToParent(bn)}
value={values[name]}
width={width}
{...otherProps}
/>
<ErrorMessage error={errors[name]} visible={touched[name]} />
</>
);
}
Parent Component:
...
const [bn, setBN] = useState("");
const childToParent = (childdata) => {
setBN(childdata);
console.log(childdata);
};
console.log("bn");
console.log(bn);
...
return (
...
<UppFormField
keyboardType="numeric"
autoCorrect={false}
// icon="bank"
name="acct_number"
placeholder="Account Number"
style={{ paddingRight: 50 }}
childToParent={childToParent}
/>
...
)
Make a middle function called
const onTextChange = (text) => {
setFieldValue(text)
parentFunction(text)
}
then TextInput takes has
onChangeText={onTextChange}

How to change state with useState hook using a variable

I have a FlatList with about 60 items.
Each item has a small button that is clicked to display more information inside the FlatList item.
<View style={styles.infoIcon} >
<TouchableOpacity onPress={() => { toggleInfo() }} >
<Ionicons name="ios-information-circle" size={40} color={"#0ca9dd"} />
</TouchableOpacity >
</View>
{showInfo ? <View><Text>{ itemData.item.info }</Text><View> : null }
The onPress toggle function is something like:
const toggleInfo = () => {
if (showInfo === true) {
setShowInfo(false);
} else {
setShowInfo(true);
}
};
Of course, since it's a FlatList, when I click the button all of the FlatList items show their hidden contents. But I only want the info for the clicked item to show, leaving all the others unchanged.
So, I changed the onPress to take an argument:
<TouchableOpacity onPress={() => { toggleInfo(itemData.item.id) }} >
...which is fine. But now I need to target the right state array (which is the same as the id but with an "z" tacked on the end to avoid any variable conflicts):
const toggleInfo =(id) => { // id might be "ABC"
const infoState = `${id}z`;
const infoStateSET = `set${speciesState}`; // therefore: setABCz
// Now I want to target the state "ABCz" and "setABCz" useState variables
if (infoState === true) {
infoStateSET(false);
} else {
infoStateSET(true);
}
};
Now, obviously there is no literal "infoStateSET" to change the state but I do want to use the variable to target the set state function.
Is this possible?
You can just set the id in showInfo state and then check if showInfo id is the same as the itemData.item.id.
basically you would have a state like this.
const [showInfo, setShowInfo] = useState(null);
Then you would set the state like so using your toggleInfo function:
const toggleInfo = (id) => {
if (showInfo === id) {
setShowInfo(id);
} else {
setShowInfo(null);
}
}
Then in your Flatlist item:
<View style={styles.infoIcon} >
<TouchableOpacity onPress={() => { toggleInfo(itemData.item.id) }} >
<Ionicons name="ios-information-circle" size={40} color={"#0ca9dd"} />
</TouchableOpacity >
</View>
{showInfo === itemData.item.id ? <View><Text>{ itemData.item.info }</Text><View> : null }

onChangeText of InputField issue in React Native

I am working on a ReactNative application. I have some input fields, on button click if any of these fields is empty i have to show validation error. My code is:
<View>
<InputField placeholder="Teilnummer"
onChangeText={(nm)=> this.setState({pTeilnummer: nm})}
/>
<View>
{
this.state.ErrorTeilnummer ? <Text style={styles.ValidationErrorMessage}> * Required </Text> : null
}
</View>
<InputField placeholder="Teilbenennung"
onChangeText={(nm)=> this.setState({pTeilbenennung: nm})}
/>
<View>
{
this.state.ErrorTeilbenennung ? <Text style={styles.ValidationErrorMessage}> * Required </Text> : null
}
</View>
<InputField placeholder="Lieferant"
onChangeText={(nm)=> this.setState({pLieferant: nm})}
/>
<View>
{
this.state.ErrorLieferant ? <Text style={styles.ValidationErrorMessage}> * Required </Text> : null
}
</View>
<Button title="Speichern" color="#ee7100" onPress={() => { this._addProject(this.state.pTeilnummer + "_" + this.state.pTeilbenennung + "_" + this.state.pLieferant, this.state.pdate)}}/>
</View>
I have declared these states as:
constructor(props){
this.state = {ErrorTeilbenennung: false, ErrorTeilnummer: false, ErrorLieferant: false pTeilbenennung: null, pTeilnummer: null, pLieferant: null};
My button click code is:
_addProject = (name, date) =>{
teilbenennung = this.state.pTeilbenennung;
teilnummer = this.state.pTeilnummer;
lieferant = this.state.pLieferant;
var selectedCheck = this.state.addCheck
if(teilbenennung == null || teilnummer == null || lieferant == null)
{
if(teilbenennung == null)
this.setState({ErrorTeilbenennung: true})
else
this.setState({ErrorTeilbenennung: false})
if(teilnummer == null)
this.setState({ErrorTeilnummer: true})
else
this.setState({ErrorTeilnummer: false})
if(lieferant == null)
this.setState({ErrorLieferant: true})
else
this.setState({ErrorLieferant: false})
}
else
{ // saving to database
}
}
When i click on the button first time i get the required validation errors. But after i type something in the first InputField and presses the button, i still get the validation error against that field (may be there is some issue with "onChangeText"), but if i click the button again then the validation error against that field is removed (i mean i have to click twice). Let me add one more thing, when i click on the InputField to write something in it the component reloads. How can i remove this issue so that it works fine with single click
I made an example to solve your problem. This is how you solve the problem you want.
Comparing the status values separately is a very inconvenient way. We can solve this problem sufficiently through onChangeText
Example is here ExampleLink
import React, { Component } from 'react';
import { AppRegistry, TextInput,View,Text,Button } from 'react-native';
export default class UselessTextInput extends Component {
constructor(props) {
super(props);
this.state = {
text: '',error1 : "error1" ,
text2: '',error2 : "error2" };
}
checkfunc() {
if(this.state.text !== '' && this.state.text2 !== ''){
alert("sucess");
} else {
alert("faild");
}
}
render() {
return (
<View style={{flex:1,alignItems:"center" , justifyContent:"center"}}>
<TextInput
style={{height: 40, borderColor: 'gray', borderWidth: 1}}
onChangeText={(text) => this.setState({text})}
value={this.state.text}
/>
{this.state.text !== '' ? null : (<Text>{this.state.error1}</Text>)}
<TextInput
style={{height: 40, borderColor: 'gray', borderWidth: 1}}
onChangeText={(text2) => this.setState({text2})}
value={this.state.text2}
/>
{this.state.text2 !== '' ? null : (<Text>{this.state.error2}</Text>)}
<Button title="checkinput" onPress={() => this.checkfunc()}/>
</View>
);
}
}
// skip this line if using Create React Native App
AppRegistry.registerComponent('AwesomeProject', () => UselessTextInput);
Issue was that my view was inside KeyboardAwareScrollView, so the first click closes the keyboard, that's why my button click does not trigger on first click. This can be resolved in two ways:
Use ScrollView instead of KeyboardAwareScrollView
Set keyboardShouldPersistTaps to true like this:
<KeyboardAwareScrollView keyboardShouldPersistTaps={true}>

Not able to set active and inactive images in React Native

I am showing custom tab-bar in my application which is showing at centre of the screen. So, Each time one tab should be active and other tabs will be inactive state.
According to that, I have implemented logic(bool values) and tried to change images, But, It's not working.
My requirement is
I have 4 tabs, suppose if user tap on 1st tab, I have to set active
image to 1st tab then rest of 3 tabs with inactive images according to
those titles (different inactive) images.
Its like for all tabs active and inactive states, each time one tab
only active state.
It's showing undefined and even if and else if conditions executing, But, nothing changing images.
Here is my code
constructor(props) {
super(props);
// this.state = { dataArray: getListData()}
this.state = { selectedTab: 'Value', flagImage:true, flagForTelugu: false, flagForTamil: false, flagForHindi: false, flagForEnglish: false}
}
OnTabItemHandler = (tabItem) => {
this.setState({selectedTab: tabItem,flagImage:this.state.flagImage})
}
renderBottomContent = (item) => {
const {selectedTab, dataArray, flagForTelugu, flagForTamil, flagForHindi, flagForEnglish} = this.state
this.state = { dataArray: getListData()}
if (selectedTab === ‘Telugu’) {
this.flagForTelugu = true
this.flagForTamil = false
this.flagForHindi = false
this.flagForEnglish = false
} else if (selectedTab === ‘Tamil’) {
this.flagForTamil = true
this.flagForTelugu = false
this.flagForHindi = false
this.flagForEnglish = false
} else if (selectedTab === ‘Hindi’) {
this.flagForHindi = true
this.flagForTamil = false
this.flagForTelugu = false
this.flagForEnglish = false
} else if (selectedTab === ‘English’) {
this.flagForEnglish = true
this.flagForTamil = false
this.flagForTelugu = false
this.flagForHindi = false
}
//loading some other text here in bottom
}
render(item) {
const {selectedTab, flagForTelugu, flagForTamil, flagForHindi, flagForEnglish} = this.state;
return (
<View style={styles.container}>
<View style = {styles.tabContainer}>
<TouchableOpacity style={styles.tabIcons} onPress={() => this.OnTabItemHandler(‘Telugu’)}>
<Image
style={styles.tabItemsImages}
source={this.state.flagImage === true ?
teluguActiveImage :
teluguDeActiveImage}
/>
</TouchableOpacity>
<Text style={styles.tabTextItems} onPress={() => this.OnTabItemHandler('Telugu')}>Telugu</Text>
</View>
<View style = {styles.tabContainer}>
<TouchableOpacity style={styles.tabIcons} onPress={() => this.OnTabItemHandler(‘Tamil’)}>
<Image
style={styles.tabItemsImages}
source={this.state.flagImage === true ?
tamilActiveImage :
tamilDeActiveImage}
/>
</TouchableOpacity>
<Text style={styles.tabTextItems} onPress={() => this.OnTabItemHandler('Tamil')}> Tamil </Text>
</View>
<View style = {styles.tabContainer}>
<TouchableOpacity style={styles.tabIcons} onPress={() => this.OnTabItemHandler(‘Hindi’)}>
<Image
style={styles.tabItemsImages}
source={this.state.flagImage === true ?
hindiActiveImage :
hindiDeActiveImage}
/>
</TouchableOpacity>
<Text style={styles.tabTextItems} onPress={() => this.OnTabItemHandler('Hindi')}> Hindi </Text>
</View>
<View style = {styles.tabContainer}>
<TouchableOpacity style={styles.tabIcons} onPress={() => this.OnTabItemHandler(‘English’)}>
<Image
style={styles.tabItemsImages}
source={this.state.flagImage === true ?
englishActiveImage :
englishDeActiveImage}
/>
</TouchableOpacity>
<Text style={styles.tabTextItems} onPress={() => this.OnTabItemHandler('English')}> English </Text>
</View>
</View>
{this.renderBottomContent(item)}
</View>
);
}
Can anyone suggest me, Where I am doing wrong?
And in the method renderBottomContent(), these flagForTelugu,
flagForTamil, flagForHindi, flagForEnglish showing as undefined while
debugging time.
I'm not good to explaining how the code works.
but the idea is you need 1 state called selectedIndex and the rest is you need to check the active image with the selectedIndex is match show the active image
the example code may looks like this:
import React, { Component } from 'react';
import RN from 'react-native';
export default class App extends Component {
constructor(props) {
super(props);
this.state={
selectedIndex:0,
//you can change every urlActive and urlInactive url to your needed image
tabList:[
{label:'tab 1', urlActive:'https://livelovely.com/static/images/full-listing/icon-modal-success%402x.png', urlInactive:'https://icon2.kisspng.com/20180823/ioc/kisspng-traffic-sign-image-traffic-code-no-symbol-inactive-symbol-www-pixshark-com-images-gallerie-5b7e884790b8a3.5710860815350190795928.jpg'},
{label:'tab 2', urlActive:'https://livelovely.com/static/images/full-listing/icon-modal-success%402x.png', urlInactive:'https://icon2.kisspng.com/20180823/ioc/kisspng-traffic-sign-image-traffic-code-no-symbol-inactive-symbol-www-pixshark-com-images-gallerie-5b7e884790b8a3.5710860815350190795928.jpg'},
{label:'tab 3', urlActive:'https://livelovely.com/static/images/full-listing/icon-modal-success%402x.png', urlInactive:'https://icon2.kisspng.com/20180823/ioc/kisspng-traffic-sign-image-traffic-code-no-symbol-inactive-symbol-www-pixshark-com-images-gallerie-5b7e884790b8a3.5710860815350190795928.jpg'},
]
}
}
render() {
console.disableYellowBox = true;
return (
<RN.View style={{flex:1}}>
//creating the tab height
<RN.View style={{flex:0.07, flexDirection:'row'}}>
{
//loop throught the state
this.state.tabList.map((item,index)=>{
return(
//the style just to make it beautiful and easy to debug
<RN.TouchableOpacity style={{flex:1, alignItems:'center', backgroundColor:index==0?'green':index==1?'blue':'yellow'}}
//this onpress to handle of active selected tab
onPress={()=>{this.setState({selectedIndex:index})}}
>
<RN.View>
<RN.Text>{item.label}</RN.Text>
<RN.Image
//here's the magic show off
source={{uri:this.state.selectedIndex==index?item.urlActive:item.urlInactive}}
style={{width:20, height:20, resizeMode:'contain'}}
/>
</RN.View>
</RN.TouchableOpacity>
)
})
}
</RN.View>
</RN.View>
);
}
}
and the result look like :