问题
I have a Formik form where I take user input input & run a query after submitting.
When I click on the search button, a list is rendered. All list items have a button of their own. When I click on the green add button (from the list items) for the first time, the button does not work. Console log's content is not printed. Instead, the onBlur event of the inputField is triggered. However, if I click on the + button again, then it works and prints no. This problem is visible in simulators/phones, not on the web mode on the sandbox.
export const AddFriendScreen: React.FunctionComponent = () => {
const initialValues: FormValues = {
input: '',
};
const [showFlatList, setShowFlatList] = useState<UsersLazyQueryHookResult>(
'',
);
const handleSubmitForm = (
values: FormValues,
helpers: FormikHelpers<FormValues>,
) => {
loadUsers({
variables: {
where: {
OR: [
{ phoneNumber: newPhoneNumber },],
},
},
});
helpers.resetForm();
};
return (
<SafeAreaView style={styles.safeAreaViewContainer}>
<View style={styles.searchTopContainer}>
<View style={styles.formContainer}>
<Formik
initialValues={initialValues}
onSubmit={handleSubmitForm}
validationSchema={validationSchema}>
{({ handleChange, handleBlur, handleSubmit, values }) => (
<View style={styles.searchFieldContainer}>
<View style={styles.form}>
<FieldInput
handleChange={handleChange}
handleBlur={handleBlur}
value={values.input}
fieldType="input"
icon="user"
placeholderText="E-Mail oder Telefonnummer oder Name"
/>
<ErrorMessage
name="input"
render={(msg) => <ErrorText errorMessage={msg} />}
/>
</View>
<View style={styles.buttonContainer}>
<ActionButton buttonText="Suchen" onPress={handleSubmit} />
</View>
</View>
)}
</Formik>
</View>
<View style={styles.listHolder}>
{data && showFlatList !== null && (
<UsersFoundList
data={data}/>
)}
</View>
</View>
</SafeAreaView>
);
};
Snack Expo:
https://snack.expo.io/@nhammad/jealous-beef-jerky
[![enter image description here][1]][1]
Edit:
Found a workaround but still open to easier solutions. Still haven't figured out what's causing the issue exactly.
回答1:
However, this causes the formik error to show up immediately after the form is submitted and data is returned/rendered. For instance, the error suggests that the input field should not be empty.
...
Why is the keyboard interfering in this?
Probably because when you call Keyboard.dismiss()
you are actually unfocusing the input, which will trigger the validateOnBlur event.
So when you unfocus a field (blur), it will try to validate (validateOnBlur), and because the field is empty, it will show the validation.
The error should only show up when we are trying to resubmit the form without an input.
If the error should only show when you submit the form, you should pass to the Formik
component validateOnBlur={false}
. With this, it won't show the error message when you call Keyboard.dismiss()
, because it will remove the validation on blur.
But it still validates when the input changes, triggering validateOnChange. You can also pass to the Formik
component validateOnChange={false}
to disable the validation on change and it will only validate when you submit the form (press the button).
Please notice that validateOnChange and validateOnBlur are true
by default.
Edit:
You need to add validateOnBlur={false}
but instead of calling Keyboard.dismiss()
you need to call fieldRef.current.blur()
. But for that to work, you need to use React.forwardRef
in your input component.
So you need to create the fieldRef
const fieldRef = useRef();
Pass to the component
<FieldInput
ref={fieldRef} // passing the ref
handleChange={handleChange}
handleBlur={handleBlur}
value={values.input}
fieldType="input"
icon="user"
placeholderText="input"
/>
And you need to wrap around your FieldInput
with React.forwardRef
and pass the ref
to the Input
component.
// wrapping the component with React.forwardRef
export const FieldInput: React.FunctionComponent<FieldInputProps> = React.forwardRef(({
handleChange,
handleBlur,
fieldType,
placeholderText,
value,
style,
rounded,
//ref,
}, ref) => {
return (
<Item rounded={rounded} style={[styles.inputItem, style]}>
<Input
ref={ref} // passing the ref
autoFocus={true}
autoCapitalize="none"
style={styles.inputField}
placeholder={placeholderText}
keyboardType="default"
onChangeText={handleChange(fieldType)}
onBlur={handleChange(fieldType)}
value={value}
/>
</Item>
);
});
And now in the handleSubmitForm
you call fieldRef.current.blur()
const handleSubmitForm = (
values: FormValues,
helpers: FormikHelpers<FormValues>,
) => {
// other logic from your submit
if (fieldRef && fieldRef.current)
fieldRef.current.blur();
};
With this, you will solve the problems of your question and from the comments.
Working example
Explanation about useRef
We need to use the useRef
hook so we can get the element of the Input
component to be able to call the blur
function so don't be focused in the input and can click in the plus button.
We need to use the useRef
hook because that is how you create a ref
in functional components.
来源:https://stackoverflow.com/questions/63667170/touched-property-not-being-reset