How to validate useRef object with yup? - react-native

I am using formik and yup to validate inputs of form in React Native. I validated everything except Date Of Birth which uses useRef:
const dob = useRef("Birth Date");
{/* Date Of Birth */}
<View>
<TouchableOpacity onPress={showDatepicker}>
<View>
<Text>{dob.current}</Text>
</View>
</TouchableOpacity>
<View>
{showDOB && (
<View style={{ marginBottom: 25 }}>
<DateTimePicker testID="dateTimePicker" value={date} mode="date" is24Hour={false} display="spinner" onChange={onChange} dateFormat="day month" />
</View>
)}
</View>
</View>
<Text style={{ color: "#FF6B6B" }}>{formikProps.errors.dob}</Text>
In validationSchema:
dob: yup.string().required("required"),
but I get following error:
dob must be a `string` type, but the final value was : `{"current": "\Birth Date\"}`
How do I resolve this issue?
Thank you in advance.

I don‘t know yup but can‘t you just define current instead of dob?
dob:{ current: yup.string().required("required") }

You can validate objects with yup.object().shape();
So for instance validating an object with current that is a string would be:
const dob = { current: 'hello' }
const schema = yup.object().shape({
current: yup.string().required(),
});
schema.isValid(dob) // Promise

Related

Modal doesnt open when clicking on TouchableOpacity - React Native

I am trying to implement the modal component in this app and for some reasons, I cant make it work. I have done it in another app and even though everything looks as it should in this one, it still doesn't work, it just doesn't toggle!
Here is my code (i call toogleModal() here ):
<TouchableOpacity
activeOpacity={1}
style={styles.slideInnerContainer}
//onPress={() => { alert(`You've clicked '${rest_name}'`); }}
onPress={() => this.toggleModal(rest_name)}
>
<View style={styles.shadow} />
<View style={[styles.imageContainer, even ? styles.imageContainerEven : {}]}>
{this.image}
<View style={[styles.radiusMask, even ? styles.radiusMaskEven : {}]} />
</View>
<View style={[styles.textContainer, even ? styles.textContainerEven : {}]}>
<View style={{ flexDirection: 'row' }}>
{uppercaseTitle}
{ratings}
</View>
<Text
style={[styles.subtitle, even ? styles.subtitleEven : {}]}
numberOfLines={2}
>
{rest_location}
</Text>
</View>
</TouchableOpacity>
Now here is the toggleModal() which should set the state and then call the onPressItem() :
toggleModal = (item) => {
this.setState({ isModalVisible: !this.state.isModalVisible });
this.onPressItem(item);
};
and onPressItem() :
onPressItem = (item) => {
return (
<ThemeProvider theme={theme}>
<Modal animationIn="rubberBand" animationOut={"bounceOut"}
isVisible={this.state.isModalVisible}
onBackdropPress={() => this.setState({ isModalVisible: false })}
>
<View style={{ flex: 1 }}>
{item}
</View>
<View style={{ flex: 1 }}>
<Button title="Hide modal" onPress={this.toggleModal} />
</View>
</Modal>
</ThemeProvider>
)
};
Now, remember this code is taken from another app where modal is working perfectly!
Most probably your issue with click option is connected with incorrect import TouchableOpacity from correct module. Check if you are importing from react-native:
import { TouchableOpacity } from 'react-native';
change this line
onPress={() => this.toggleModal(rest_name)}
to this:
onPress={() => {this.toggleModal(rest_name)}}
you only need to put the function call in brackets

Fetching nested data, undefined is not an object

I'm trying to fetch data from API, but I'm only able to fetch the highest level ones. When I'm trying to access ones nested under categories, I get an error: undefined is not an object (evaluating 'this.state.data.order.name' ).
From what I've read it might be an issue with state but I'm new to react-native and I am not sure how to fix it.
This is the API structure
render(){
const { data } = this.state;
return(
<ScrollView style={styles.containerxd}>
<TouchableOpacity style={styles.textStyle}>
<Image
source={require('./images/burger.png')}
style={styles.ImageIconStyle} />
</TouchableOpacity>
<View style={styles.white}>
<View style={{flex:1, alignItems:'center', justifyContent:'center'}}>
<View style={styles.tabHeader}><Text style={styles.textHeader}>Scientific name</Text></View>
<View style={styles.tabContent}><Text style={styles.textContent}>{this.state.data.scientific_name}</Text></View>
<View style={styles.tabHeader}><Text style={styles.textHeader}>Common name</Text></View>
<View style={styles.tabContent}><Text style={styles.textContent}>{this.state.data.common_name}</Text></View>
<View style={styles.tabHeader}><Text style={styles.textHeader}>Moisture use</Text></View>
<View style={styles.tabContent}><Text style={styles.textContent}>{this.state.data.order.name}</Text></View>
Scientific name and common name show up just fine, but every data level lower renders error.
You need to validate your data.When order is undefined, doing order.name will break your app. change
<View style={styles.tabContent}><Text style={styles.textContent}>{this.state.data.order.name}</Text></View>
to
const { data } = this.state;
const name = data && data.order && data.order.name || '';
// rest of the code here
<View style={styles.tabContent}><Text style={styles.textContent}>{name}</Text></View>
NOTE
Always validate your data. Don't assume that you'll always get the right data. When working with objects always validate them, as doing data.name, can break your app, if data is null or undefined. for example, given the following object.
const animal = {};
doing
// throws an error, Cannot read property 'toLowerCase' of undefined
console.log(animal.name.toLowerCase())
to prevent that from happening, we need to check if the propery exists, like the following.
// checks if the name property exists console name, else assign a console log 'Lion'
console.log(animal.name && animal.name.toLowerCase() || 'Lion')
Second option
add a loader, display Loading... text when fetching data from api, once the request finish set loader to false and display your data.
fetchData = async () => {
const res = await fetch(...)
...
this.setState({ isLoading: false, data: response.data });
}
render() {
return (
<ScrollView style={styles.containerxd}>
<TouchableOpacity style={styles.textStyle}>
<Image
source={require('./images/burger.png')}
style={styles.ImageIconStyle}
/>
</TouchableOpacity>
{this.state.isLoading ? (
<Text>Loading...</Text>
) : (
<View style={styles.white}>
<View
style={{
flex: 1,
alignItems: 'center',
justifyContent: 'center'
}}
>
<View style={styles.tabHeader}>
<Text style={styles.textHeader}>Scientific name</Text>
</View>
<View style={styles.tabContent}>
<Text style={styles.textContent}>
{this.state.data.scientific_name}
</Text>
</View>
<View style={styles.tabHeader}>
<Text style={styles.textHeader}>Common name</Text>
</View>
<View style={styles.tabContent}>
<Text style={styles.textContent}>
{this.state.data.common_name}
</Text>
</View>
<View style={styles.tabHeader}>
<Text style={styles.textHeader}>Moisture use</Text>
</View>
<View style={styles.tabContent}>
<Text style={styles.textContent}>
{this.state.data.order.name}
</Text>
</View>
</View>
</View>
)}
</ScrollView>
);
}

Invarient Violation: Text strings must be rendered within a <Text> component , Occurs when using conditional operator in React Native

After using conditional operator to display some components based on some conditions, I got this error. Following is the code.
{this.state.isOk==false ? (
<View>
<TextInput value={this.state.title } />
<Text style={LocalStyles.errorText}>{this.state.errorTitle}</Text>
<TextInput value={ this.state.company } />
<Text style={LocalStyles.errorText}>{this.state.errorCompany}</Text>
<View>
<CheckBox value={this.state.isCurrent} />
</View>
{this.state.isCurrent==false ? (
<Date
value={this.state.from }
placeholder={strings("user_profile.from")}
maxDate={moment().subtract(1, "years")}
onChange={time => {
this.setState({ from: time });
}}/>
<Text style={LocalStyles.errorText}>{this.state.errorDate}</Text>
) : null}
<TextInput label={this.state.location} />
<Text style={LocalStyles.errorText}>{this.state.errorLocation}</Text>
<TextInput multiline={true} value={ this.state.description} />
<Text style={LocalStyles.errorText}>{this.state.errorDesc}</Text>
</View>
): null}
this is the style for Text component
errorText: {
color: "red",
paddingLeft: 10,
paddingRight: 10,
flexDirection: 'row',
},
Instead of returning null, which is handled like a text in this context, you should return an empty <View/>.

textinput value on scrollview

i want to change value of textInput but it change all value of textinput , i know because of the state, but what the right way to handle this textInput or what i use is numericInput from react-native-numeric-input, thanks for helping.
<ScrollView>
{this.state.display.map((info)=>{
return
<View style={{paddingBottom:5,alignSelf:'center'}} key={info.id}>
<View style={{ ... }}>
<View style={{flexDirection:'row'}}>
...
<View style={{justifyContent:'center',marginLeft:'auto',marginRight:10}}>
<NumericInput
totalWidth={70}
totalHeight={30}
iconSize={10}
initValue={this.state.v6}
value={this.state.v6}
onChange={(v6) => this.setState({ v6 })}
rounded
textColor='#59656F'
iconStyle={{ color: 'white' }}
rightButtonBackgroundColor='#AC9FBB'
leftButtonBackgroundColor='#DDBDD5'
/>
</View>
</View>
</View>
</View>
})}
</ScrollView>
and this my state code
state={
v6:0
}
Try changing the onChange to this:
onChange={(value) => this.setState({ v6: value })}

React Native clear text multiple TextInput boxes

I found example code on a facebook React Native page which shows how to use setNativeProp to clear text on a click but I can't see how to do it with multiple text boxes. Here is the code:
var App = React.createClass({
clearText() {
this._textInput.setNativeProps({text: ''});
},
render() {
return (
<View style={styles.container}>
<TextInput ref={component => this._textInput = component}
style={styles.textInput} />
<TouchableOpacity onPress={this.clearText}>
<Text>Clear text</Text>
</TouchableOpacity>
</View>
);
}
});
The ref seems to be fixed in the function so will always target the same TextInput box. How can I alter the function to target any TextInput box I indicate?
This should work. Notice that the ref on the TextInput needs to be the one you call from the clearText functino.
var App = React.createClass({
clearText(fieldName) {
this.refs[fieldName].setNativeProps({text: ''});
},
render() {
return (
<View style={styles.container}>
<TextInput ref={'textInput1'} style={styles.textInput} />
<TouchableOpacity onPress={() => this.clearText('textInput1')}>
<Text>Clear text</Text>
</TouchableOpacity>
<TextInput ref={'textInput2'} style={styles.textInput} />
<TouchableOpacity onPress={() => this.clearText('textInput2')}>
<Text>Clear text</Text>
</TouchableOpacity>
</View>
);
}
});
Updated my answer to clear different fields.
You can also use something like this to clear the text of TextInput.
clearText(fieldName) {
this.refs[fieldName].clear(0);
},