I am using react-native. How can I move this part of the code below, into the AppForm component file? And everything still work.
{({
handleChange,
handleBlur,
handleSubmit,
values,
errors,
isValid,
}) => (
AppForm component
<Formik
initialValues={initialValues}
onSubmit={onSubmit}
validationSchema={validationSchema}
style={[style, styles.form]}>
{children}
</Formik>
AppForm component being used
<AppForm
validationSchema={loginValidationSchema}
initialValues={{email: '', password: ''}}
onSubmit={(values: {email: string; password: string}) => {
login(values.email, values.password);
}}>
{({
handleChange,
handleBlur,
handleSubmit,
values,
errors,
isValid,
}) => (
<View>
<AppInputField
style={{
backgroundColor: 'white',
}}
placeholder="Email Address"
onChange={handleChange('email')}
onBlur={handleBlur('email')}
..........
I want to remove the code from this file ^ and move it into the AppForm component. Not sure how that will work...
Related
I saw same question a couple of times but none of the answers made sense or solved it so maybe someone could help! I want to replace formiks onchange function with my own custom usestate hook. However, when I do that none of the validations work anymore, strangely none accept the error that field is required stays. Anyone know how to do it? Thanks!!
const DisplayingErrorMessagesSchema = Yup.object().shape({
password: Yup.string()
.min(2, 'Too Short!')
.max(50, 'Too Long!')
.required('Required'),
email: Yup
.string()
.email('Invalid email')
.required('Required')
.min(2, ({ min }) => `Password must be at least ${min} characters`)
});
const App = () => {
const { formData, handleInputChange } = useForm(
{
email: "",
password: ""
}
);
return (
<>
<Formik
initialValues={formData}
validationSchema={DisplayingErrorMessagesSchema}
onSubmit={values => console.log(values)}
>
{({ handleSubmit, isValid, values }) => (
<>
<Field
component={CustomInput}
name="title"
placeholder="Title"
/>
<Field
component={CustomInput}
name="post"
placeholder="Write post..."
multiline
numberOfLines={3}
/>
<Button
onPress={handleSubmit}
title="POST"
disabled={!isValid}
/>
</>
)}
</Formik>
</>
)
}
const CustomInput = (props) => {
const {
field: { name, onBlur, onChange, value },
form: { errors, touched, setFieldTouched },
...inputProps
} = props
const hasError = errors[name] && touched[name]
return (
<>
<TextInput
style={[
styles.textInput,
hasError && styles.errorInput
]}
value={value}
onChangeText={(text) => onChange(name)(text)}
onBlur={() => {
setFieldTouched(name)
onBlur(name)
}}
{...inputProps}
/>
{hasError && <Text style={styles.errorText}>{errors[name]}</Text>}
</>
)
}
I want to save the values from all input fields to getdata(), but I am getting undefined value
export default function Signupfor(props) {
// const phoneInput = useRef < PhoneInput > null;
const [text, setTextname] = useState();
function getdata() {
console.log('dsd');
console.log(text);
}
const {userInfo, log} = props?.route?.params;
console.log(log.name);
return (
<View style={styles.prheight}>
<View style={styles.form}>
<Text style={styles.r}>One Last Step</Text>
<TextInput
style={styles.forminput}
label="Name"
value={userInfo.user.name}
onChangeText={text => setTextname(text)}
/>
<TextInput
style={styles.forminput}
label="Email"
value={userInfo.user.email}
onChangeText={text => setTextemail(text)}
/>
<TextInput
style={styles.forminput}
label="Whatsapp Number"
keyboardType="numeric"
value={userInfo.user.number}
onChangeText={text => setTextnumber(text)}
// value={this.state.myNumber}
maxLength={10} //setting limit of input
/>
</View>
<View style={styles.buttonw}>
<Button color="#7743DB" title="Lets Go" onPress={() => getdata()} />
</View>
</View>
);
}
Here, name and email should not be able to be edited. I want to pass the value from value={userInfo.user.name} to the getdata()
you can use formik package for making form in react native
Installation
yarn add formik
Usage
import { Formik } from "formik";
export default function Signupfor(props) {
const { userInfo, log } = props?.route?.params;
console.log(log.name);
return (
<Formik
initialValues={{
name: userInfo.user.name,
email: userInfo.user.email,
number: userInfo.user.number,
}}
onSubmit={async (values, actions) => {
try {
console.log("name", values.name);
console.log("phone", values.number);
const params = {
full_name: values.name,
email: values.email,
phone_number: values.number,
};
} catch (error) {
let message = error.message;
console.log(message)
} finally {
actions.setSubmitting(false);
}
}}
>
{({
handleChange,
setFieldValue,
handleSubmit,
values,
errors,
touched,
isSubmitting,
}) => (
<View style={styles.prheight}>
<View style={styles.form}>
<Text style={styles.r}>One Last Step</Text>
<TextInput
style={styles.forminput}
label="Name"
value={values.name}
onChangeText={handleChange("name")}
/>
<TextInput
style={styles.forminput}
label="Email"
value={values.email}
onChangeText={handleChange("email")}
/>
<TextInput
style={styles.forminput}
label="Whatsapp Number"
keyboardType="numeric"
value={values.number}
onChangeText={handleChange("number")}
// value={this.state.myNumber}
maxLength={10} //setting limit of input
/>
</View>
<View style={styles.buttonw}>
<Button
color="#7743DB"
title="Lets Go"
onPress={() => handleSubmit()}
/>
</View>
</View>
)}
</Formik>
);
}
Your original method doesn't populate the state unless you edit the text input field, this is because your initialState doesn't have a value to start with. so firing getData() is reading empty state if the fields havent been changed.
onChangeText={text => setTextname(text)}
Only fire if you edit the textInput field.
Also I think you might be missing props, so first check if you are getting the correct data from props by logging it.
Once you have confirmed the props are available.
Set the initialState for name to userInfo.user.name
const { userInfo } = props?.route?.params;
const [name, setName] = useState(userInfo.user.name);
Then pass the state name to your TextInput and it should populate the value by reading from state.
return (
<>
<TextInput
placeholder="name"
value={name}
onChangeText={(text) => setName(text)}
/>
<Button title="Submit" onPress={() => getData()} />
</>
)
Make sure to create states for any additional values you wish to save.
const [name, setName] = useState(userInfo.user.name);
const [email, setEmail] = useState(userInfo.user.email);
You can use a library like https://react-hook-form.com to check an example with react native on video.
Or you can right it yourself, in the example below any time you need access to input values you can read it from text and number
const UselessTextInput = () => {
const [text, onChangeText] = useState("Useless Text");
const [number, onChangeNumber] = useState(null);
return (
<SafeAreaView>
<TextInput
style={styles.input}
onChangeText={onChangeText}
value={text}
/>
<TextInput
style={styles.input}
onChangeText={onChangeNumber}
value={number}
placeholder="useless placeholder"
keyboardType="numeric"
/>
</SafeAreaView>
);
};
You can do something like this!!
export default function Signupfor(props) {
const {userInfo, log} = props?.route?.params;
const [name, setName] = useState(userInfo?.user?.name);
const [phone, setPhone] = useState(userInfo?.user?.number);
function getdata() {
console.log("name",name)
console.log("phone",phone)
}
return (
<View style={styles.prheight}>
<View style={styles.form}>
<Text style={styles.r}>One Last Step</Text>
<TextInput
style={styles.forminput}
label="Name"
// this value must be same with useState
value={name}
onChangeText={text => setName(text)}
/>
<TextInput
style={styles.forminput}
label="Mobile"
value={phone}
onChangeText={text => setPhone(text)}
/>
</View>
<View style={styles.buttonw}>
<Button color="#7743DB" title="Lets Go" onPress={() => getdata()} />
</View>
</View>
);
}
Same goes for email.
I have this screen in react native where I want to validate the form and submit it and I have the submit button in my header. How can I get the values in handle submit which is outside the formik. Because I couldn't access the values in the custom function handleSubmit.
React.useLayoutEffect(() => {
navigation.setOptions({
headerTitleAlign: 'center',
headerTitle: () => <Text style={styles.titleHeader}>Payment Method</Text>,
headerRight: () => (
<Pressable onPress={handleSubmit}>
<Text>Done</Text>
</Pressable>
),
});
}, [navigation, userId]);
const handleSubmit = async (values: any) => {
const data: any = {
paymentServiceTypeId: defaultPaymentType,
invoiceNeeded,
companyName: company,
vatNumber,
}
console.log(values);
};
return (
<Formik
initialValues={initialState}
onSubmit={(values) => handleSubmit(values)}
validationSchema={getValidationSchema(staticValues.static)}
>
{({ handleChange, handleBlur, values, touched, errors, setFieldValue }) => (
<>
{defaultPaymentType == 2 && (
<>
<Text style={styles.title}>Company Name</Text>
<View style={styles.textInputView}>
<TextInput
style={styles.inputText}
placeholder={'Company Name'}
value={values.company}
onChangeText={handleChange('company')}
onBlur={handleBlur('company')}
/>
{touched.company && errors.company && <Text style=
{styles.errorText}>{errors.company}</Text>}
<>
)}
</Formik>
By using const formRef = useRef(); and then
<Formik
...
innerRef={formRef}
/>
Now where you need values, get them from formRef.current.values;
This issue can easily be fixed by using useFormik which separates the form from the values and handlers being used by formik. So, even if you have the submit button outside the form, you can use the handleSubmit provided by the Formik.
How can i use Dropdown picker setValue with Formik? handleChange or setValueField doesn't work properly. Any suggestions?
const [open, setOpen] = useState(false);
const items = [
{ label: 'Apple', value: 'apple' },
{ label: 'Banana', value: 'banana' },
];
return (
<Formik
initialValues={{ fruits: [] }}
onSubmit={values => console.log(values)}
>
{({ handleChange, handleSubmit, values }) => (
<View>
<DropdownPicker
schema={{ label: 'label', value: 'label' }}
open={open}
setOpen={setOpen}
value={values.fruits}
setValue={handleChange('fruits')}
items={items}
multiple
/>
<Button onPress={handleSubmit} title="Submit" />
</View>
)}
</Formik>
);
};```
You could wrap DropdownPicker in another component and use useFormikContext and useField formik hooks to be able to use it, take a look in this example:
import { useFormikContext, useField } from "formik";
import React, { useState } from "react";
import DropDownPicker from "react-native-dropdown-picker";
const DropDownFormik = ({ ...props }) => {
const [openProvider, setOpenProvider] = useState(false);
const { setFieldValue } = useFormikContext();
const [field] = useField(props);
return (
<DropDownPicker
{...field}
{...props}
value={field.value}
open={openProvider}
setOpen={setOpenProvider}
setValue={(val) => {
setFieldValue(field.name, val());
}}
/>
);
};
export default DropDownFormik;
to use this component just specify the name in your form:
<Formik
initialValues={{ level: ""}}
onSubmit={(values) => console.log(values)}
>
{({ handleChange, handleBlur, handleSubmit, values }) => (
<View>
<DropDownFormik
zIndex={3000}
name="level"
placeholder="Notification Level"
items={notificationLevels}
/>
</View>
)}
</Formik>
I wanted to show a list of data fetched from API inside DropdownModal (https://github.com/sohobloo/react-native-modal-dropdown) . The data is user address consists of name , state , country and all related to address . But it won't show inside the dropdown and it shows loading icon which means it is null or undefined . But i did have the data fetched from the API which i verify by making alert to error and result ( yup both giving the same data which is the address ) .
Below are my code .
const {getAddresses} = auth;
var {width, height} = Dimensions.get('window');
class RegisterEventOne extends React.Component {
constructor(props) {
super(props);
this.state = {
event_id: '',
tshirt_size: '',
size: '',
address: '',
addressx: '',
};
this.onResult = this.onResult.bind(this);
this.onError = this.onError.bind(this);
}
handleWithDropdownCategory = id => {
this.setState({event_id: id});
};
handleWithDropdownSize = size => {
this.setState({tshirt_size: size});
};
TShirtSize = size => {
this.setState({size: size});
};
setAddress = address => {
this.setState({addressx: address})
}
componentDidMount() {
this.props.getAddresses(this.props.event.id, this.onResult, this.onError);
}
onError(error) {
alert(JSON.stringify(error));
}
onResult(result) {
this.setState({
address: result,
});
}
render() {
return (
<React.Fragment>
<StatusBar backgroundColor="black" barStyle="light-content" />
<SafeAreaView style={styles.container}>
<ScrollView
contentInsetAdjustmentBehavior="automatic"
style={styles.scrollView}>
<View>
<Text style={styles.eventname}>{this.props.event.name}</Text>
<ModalDropdown
dropdownStyle={styles.dropdown}
dropdownTextStyle={{fontSize:15}}
style={styles.dropdown}
onSelect={(index, value) => {
this.handleWithDropdownCategory(value);
}}
options={this.props.event.categories.map(function(event) {
return event.name;
})}>
<View style={styles.dropdowncontainer}>
<Text>{this.state.event_id === '' ? 'Select Category' : this.state.event_id}</Text>
<Ionicons name="ios-arrow-down" size={20} color="black" />
</View>
</ModalDropdown>
<ModalDropdown
dropdownStyle={styles.dropdown}
dropdownTextStyle={{fontSize:15}}
style={styles.dropdown}
onSelect={(index, value) => {
this.handleWithDropdownSize(value);
this.TShirtSize(index+1);
}}
options={this.props.event.tshirts.map(function(event, index) {
return event.size;
})}
>
<View style={styles.dropdowncontainer}>
<Text>{this.state.tshirt_size === '' ? 'Select Tshirt Size' : this.state.tshirt_size}</Text>
<Ionicons name="ios-arrow-down" size={20} color="black" />
</View>
</ModalDropdown>
<ModalDropdown
dropdownStyle={styles.dropdown}
style={styles.dropdown}
dropdownTextStyle={{fontSize:15}}
onSelect={(index, value) => {
this.setAddress(value);
}}
options={this.state.address !== '' ? this.state.address.map(function(address, index) {
return address.id;
}):null}
>
<View style={styles.dropdowncontainer}>
<Text>{this.state.addressx === '' ? 'Select Address' : this.state.addressx}</Text>
<Ionicons name="ios-arrow-down" size={20} color="black" />
</View>
</ModalDropdown>
{/* <Text style={styles.header}>Compete with ohters (Optional)</Text>
<TextInput
style={styles.header}
onChangeText={text => onChangeText(text)}
placeholder="Set Date & Time (Time zone)"
/> */}
{/* <View style={styles.checkboxcontainer}>
<BouncyCheckbox
textColor="#000"
fillColor="orange"
fontFamily="JosefinSans-Regular"
text="Individual Competition"
/>
<BouncyCheckbox
textColor="#000"
fillColor="orange"
fontFamily="JosefinSans-Regular"
text="Team Competition"
/>
<TextInput
style={styles.header}
onChangeText={text => onChangeText(text)}
placeholder="Team member limit"
/>
<TextInput
style={styles.header}
onChangeText={text => onChangeText(text)}
placeholder="Username / Email"
/>
<TextInput
style={styles.header}
onChangeText={text => onChangeText(text)}
placeholder="Username / Email"
/>
<TextInput
style={styles.header}
onChangeText={text => onChangeText(text)}
placeholder="Username / Email"
/>
</View> */}
</View>
</ScrollView>
<View style={styles.processIndicator}>
<TouchableOpacity disabled>
<Text style={styles.textProcessPrimary}>Previous</Text>
</TouchableOpacity>
<TouchableOpacity onPress={()=>Actions.RegisterEventThree({event_id: this.props.event.categories[0].event_id, category_id: this.state.event_id, size: this.state.size, address: this.state.addressx})}>
<Text style={styles.textProcessPrimary}>Next</Text>
</TouchableOpacity>
</View>
</SafeAreaView>
</React.Fragment>
);
}
}
export default connect(
null,
{getAddresses},
)(RegisterEventOne);
The API :
export function getAddresses(data, callback) {
AsyncStorage.getItem('token').then(value => {
const token = JSON.parse(value);
fetch('https:apiurl.com', {
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: 'bearer' + token.access_token,
},
})
.then(response => response.json())
.then(response => callback(response.data))
.catch(error => callback(false, null, error.json()));
The loading indicator shows only if data(options) is undefined or null. Which means that you have no data at all, or data structure is bad.
You'v said that error alert is also triggered, which is not really a great thing. I don't know why the error is showing you some data tho. (except of error data).
Options should be passed in this format: ['data1', 'data2'].
Also, your taking the data from redux => this.props.event.categories instead of state. If you want to use redux, then you are missing some kind of mapStateToProps in connect fnc.
There is a lot of wrong patterns in this code. take a look at some examples of how to use redux and also take a look at examples in react-native-modal-dropdown github repo if you want to use that.
It's solved now .
I just added ,true,null behind response.data .
It would look like this :
.then(response => callback(response.data,true,null)