I have a form that uses Formik and contains two fields - email
and siteID
The email
field uses a TextInput
whereas siteID
comes from my own component called DropDown
that uses react-native-dropdown-picker
When my form is submitted I can see the value of email
within handleSubmit()
but siteID
remains as 0 and not the selected value.
How can I access the selected value from my DropDown
child component when submitting the parent form?
My form
return (
<SafeAreaView style={{ flex: 1 }}>
<View style={styles.loginContainer}>
<Formik
validationSchema={loginValidationSchema}
initialValues={{
siteID: 0,
email: "",
}}
onSubmit={(values) => handleSubmit(values)}
>
{({
handleChange,
handleBlur,
handleSubmit,
values,
errors,
isValid,
}) => (
<>
<Text style={styles.label}>Email</Text>
<TextInput
name="email"
style={styles.textInput}
onChangeText={handleChange("email")}
onBlur={handleBlur("email")}
value={values.email}
keyboardType="email-address"
/>
<DropDown name="siteID" />
</>
)}
</Formik>
</View>
</SafeAreaView>
);
DropDown component
import * as React from 'react';
import {StyleSheet} from 'react-native';
import DropDownPicker from 'react-native-dropdown-picker';
import {usePostRequest} from '../../client';
import {useState, useEffect} from 'react';
const DropDown = () => {
const [pickeropen, pickersetOpen] = useState(false);
const [pickervalue, pickersetValue] = useState(null);
const [pickeritems, pickersetItems] = useState([]);
const {status: siteStatus, data: siteData} = usePostRequest('/api/sites', {});
useEffect(() => {
console.log('siteData', siteData);
if (siteData.count) {
const sitesList = [];
siteData.results.map((item, key) =>
sitesList.push({label: item.siteName, value: item.siteID})
);
pickersetItems(sitesList);
}
}, [siteData]);
return (
<DropDownPicker
style={styles.textInput}
placeholder="Please chose a site"
open={pickeropen}
value={pickervalue}
items={pickeritems}
setOpen={pickersetOpen}
setValue={pickersetValue}
setItems={pickersetItems}
/>
);
};
CodePudding user response:
You can use setFieldValue provided by Formik to set a field manually.
A good example of usage is provided in this example
You can pass setFieldValue to your DropDown Component:
return (
<SafeAreaView style={{ flex: 1 }}>
<View style={styles.loginContainer}>
<Formik
validationSchema={loginValidationSchema}
initialValues={{
siteID: 0,
email: "",
}}
onSubmit={(values) => handleSubmit(values)}
>
{({
handleChange,
handleBlur,
handleSubmit,
values,
errors,
isValid,
setFieldValue,
}) => (
<>
<Text style={styles.label}>Email</Text>
<TextInput
name="email"
style={styles.textInput}
onChangeText={handleChange("email")}
onBlur={handleBlur("email")}
value={values.email}
keyboardType="email-address"
/>
<DropDown name="siteID" setSiteID={setFieldValue} />
</>
)}
</Formik>
</View>
</SafeAreaView>
);
And trigger it from inside of the DropDown Component:
const DropDown = ({ setSiteID }) => {
const [pickeropen, pickersetOpen] = useState(false);
const [pickervalue, pickersetValue] = useState(null);
const [pickeritems, pickersetItems] = useState([]);
const {status: siteStatus, data: siteData} = usePostRequest('/api/sites', {});
useEffect(() => {
console.log('siteData', siteData);
if (siteData.count) {
const sitesList = [];
siteData.results.map((item, key) =>
sitesList.push({label: item.siteName, value: item.siteID})
);
pickersetItems(sitesList);
}
}, [siteData]);
// You can use useEffect or create a custom handleValueChange
// and pass it to DropDownPicker
useEffect(() => {
setSiteID('siteID', pickervalue);
}, [pickersetValue])
return (
<DropDownPicker
style={styles.textInput}
placeholder="Please chose a site"
open={pickeropen}
value={pickervalue}
items={pickeritems}
setOpen={pickersetOpen}
setValue={pickersetValue}
setItems={pickersetItems}
/>
);
};
CodePudding user response:
Based on the docs, to use your own component, you should wrap your component in a Field
as follows:
const DropDownField = <Field name="siteId" component={DropDown} />
When using a Field
formik will inject props (name, value, onChange, onBlur) into your component allowing you to control the form state.
So you can then redeclare your component with those props as follows:
import * as React from 'react';
import {StyleSheet} from 'react-native';
import DropDownPicker from 'react-native-dropdown-picker';
import {usePostRequest} from '../../client';
import {useState, useEffect} from 'react';
const DropDown = ({ field: { name, value, onChange }) => {
const [pickeropen, pickersetOpen] = useState(false);
const [pickeritems, pickersetItems] = useState([]);
const {status: siteStatus, data: siteData} = usePostRequest('/api/sites', {});
useEffect(() => {
console.log('siteData', siteData);
if (siteData.count) {
const sitesList = [];
siteData.results.map((item, key) =>
sitesList.push({label: item.siteName, value: item.siteID})
);
pickersetItems(sitesList);
}
}, [siteData]);
return (
<DropDownPicker
style={styles.textInput}
placeholder="Please chose a site"
open={pickeropen}
value={value}
items={pickeritems}
setOpen={pickersetOpen}
setValue={onChange}
setItems={pickersetItems}
name={name}
/>
);
};
Essentially you wire your component up to the onChange
and value
props. Since you assigned a name
of siteId to the DropDownField
component (which you should now use in your form), any time you call onChange
site Id will update.
CodePudding user response:
try this,
get setFieldValue
from formik props.
add onChangeDropdown to <Dropdown />
like,
<DropDown name="siteID" onChangeDropdown={(value)=>{ setFieldValue("siteID",value) }}/>
get the props inside Dropdown component,
const DropDown = (props) => {
add onChangeValue
prop to your DropDownPicker
onChangeValue={props.onChangeDropdown}