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}
