Using react-final-form
i am unable to forwardRef
to my TextInput
for React Native. The ref
is required for handling the Next
button in keyboards and other forced-focus events in forms.
My setup is as follows - please note that some code has been removed for simplicity so this won't cut and paste.
// FormInputGroup/index.js
import React from 'react'
import PropTypes from 'prop-types'
import { Field } from 'react-final-form'
const FormInputGroup = ({ Component, validate, ...rest }) => (
<Field component={Component} validate={validate} {...rest} />
)
FormInputGroup.propTypes = {
name: PropTypes.string.isRequired,
Component: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
validate: PropTypes.oneOfType([PropTypes.array, PropTypes.func]),
}
export default FormInputGroup
// Form/index.js
import { Form } from 'react-final-form'
import { FormInputGroup, FormInputText, ButtonPrimary } from '/somewhere/'
...
const passwordInputRef = useRef()
<Form
onSubmit={({ email, password }) => {
// submit..
}}
>
{({ handleSubmit }) => (
<>
<FormInputGroup
name="email"
Component={FormInputText}
returnKeyType="next"
onSubmitEditing={() => passwordInputRef.current.focus()}
blurOnSubmit={false}
/>
<FormInputGroup
name="password"
Component={FormInputText}
returnKeyType="go"
onSubmitEditing={handleSubmit}
ref={passwordInputRef} // <-- This does not work which i think is to be expected...
/>
<ButtonPrimary loading={loading} onPress={handleSubmit}>
Submit
</ButtonPrimary>
</>
)}
</Form>
...
// FormInputText/index.js
const FormInputText = forwardRef( // <-- added forwardRef to wrap the component
(
{
input,
meta: { touched, error },
label,
...
...rest
},
ref,
) => {
return (
<View style={styles.wrapper}>
{label ? (
<Text bold style={styles.label}>
{label}
</Text>
) : null}
<View style={styles.inputWrapper}>
<TextInput
onChangeText={input.onChange}
value={input.value}
...
ref={ref}
{...rest}
/>
</View>
</View>
)
},
)
I think the code falls down with the <FormInputGroup />
component. A clue to this is if i change the rendering on the form to be as follows;
...
<FormInputGroup
name="password"
Component={props => <FormInputText {...props} ref={passwordInputRef} />} // <-- changed
returnKeyType="go"
onSubmitEditing={handleSubmit}
/>
...
This does seem to forward the ref, but "breaks" final-form
with each keystroke dismissing the keyboard, presumably due to a re-render.
You didn't forward the ref from FormInputGroup
.
You need to capture the ref at the level it is passed down and further forward it to the children. This is how it should be:
const FormInputGroup = forwardRef(({ Component, validate, ...rest }, ref) => (
<Field ref={ref} component={Component} validate={validate} {...rest} />
))