react-hook-form: Problem using with react-native and Typescript

Describe the bug

I’m trying to use with react-native and typescript. I have a simple one field form like this:

const { register, handleSubmit, setValue, errors } = useForm();
return (
  <SafeAreaView>
    <Input {/* from react native elements */}
      keyboardType="phone-pad"
      placeholder="Phone"
      ref={register({ name: 'phone' }, { required: true })}
      onChangeText={text => setValue('phone', text)}
    />
    <Button {/* from react native elements */}
      title="Signup"
      onPress={handleSubmit(onSubmit)}
    />
  </SafeAreaView>
)

This code works. But when I typecheck the code, I get two errors.

First:

src/screens/Phone.tsx:31:9 - error TS2322: Type 'void' is not assignable to type 'string | ((instance: Input | null) => void) | RefObject<Input> | null | undefined'.

31         ref={register({ name: 'phone' }, {required: true})}
           ~~~

  node_modules/@types/react/index.d.ts:95:9
    95         ref?: LegacyRef<T>;
               ~~~
    The expected type comes from property 'ref' which is declared here on type 'IntrinsicAttributes & IntrinsicClassAttributes<Input> & Readonly<InputProps> & Readonly<{ children?: ReactNode; }>'

I guess I can solve this by just putting the register call outside the jsx, i.e not passing anything as ref to the Input element. Would that be the best approach?

Second:

src/screens/Phone.tsx:38:9 - error TS2322: Type '(e: SyntheticEvent<Element, Event>) => Promise<void>' is not assignable to type '(event: GestureResponderEvent) => void'.
  Types of parameters 'e' and 'event' are incompatible.
    Type 'GestureResponderEvent' is not assignable to type 'SyntheticEvent<Element, Event>'.
      Types of property 'nativeEvent' are incompatible.
        Type 'NativeTouchEvent' is not assignable to type 'Event'.
          Property 'bubbles' is missing in type 'NativeTouchEvent'.

38         onPress={handleSubmit(onSubmit)}
           ~~~~~~~

  node_modules/@types/react-native/index.d.ts:4768:5
    4768     onPress?: (event: GestureResponderEvent) => void;
             ~~~~~~~
    The expected type comes from property 'onPress' which is declared here on type 'IntrinsicAttributes & IntrinsicClassAttributes<Button> & Readonly<ButtonProps> & Readonly<{ children?: ReactNode; }>'

This is because of the event type. How can I mute this?

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Comments: 22 (11 by maintainers)

Most upvoted comments

you want to try use useEffect to register input instead?

useEffect(() => {
  register({ name: 'phone' }, { required: true })
}, [register])

thanks @AdhamMoussa for the update.

@bluebill1049 although Typescript doesn’t complain any more, the submit handler is not running when I press the submit button

import React from 'react';
import { View, AsyncStorage } from 'react-native';
import { Button } from 'react-native-paper';

import CustomTextInput from '../../../components/CustomTextInput';

import { useCustomForm } from '../../../hooks/useCustomForm';
import { useNavigation } from '../../../hooks/useNavigation';

import { ILoginMutationVariables, useLoginMutation } from '../../../gql/schema';
import { loginSchema } from './loginSchema';

import { styles } from './styles';

const defaultValues: ILoginMutationVariables = {
  email: '',
  password: ''
};

const LoginForm: React.FC = () => {
  const { formMethods, changeHandler } = useCustomForm<ILoginMutationVariables>(
    loginSchema,
    defaultValues
  );

  const [login] = useLoginMutation();

  const navigation = useNavigation();

  const { errors, handleSubmit, reset, watch, formState } = formMethods;
  const values = watch();

  const submitHandler = async (data: ILoginMutationVariables) => {
    try {
      const { data: loginResponse } = await login({ variables: data });

      reset(defaultValues);

      AsyncStorage.setItem(
        'auth_token',
        loginResponse?.login.authToken as string
      );

      navigation.navigate({ routeName: 'App' });
    } catch (error) {}
  };

  return (
    <View>
      <CustomTextInput
        containerStyles={styles.input}
        placeholder="Email"
        label="Email"
        textContentType="emailAddress"
        keyboardType="email-address"
        autoCompleteType="email"
        value={values.email}
        onChangeText={(value): void => changeHandler('email', value.trim())}
        error={Boolean(errors.email)}
        errorMsg={errors.email?.message?.toString()}
        disabled={formState.isSubmitting}
      />

      <CustomTextInput
        containerStyles={styles.input}
        placeholder="Password"
        label="Password"
        textContentType="password"
        autoCompleteType="password"
        returnKeyType="go"
        secureTextEntry
        onChangeText={(value): void => changeHandler('password', value.trim())}
        error={Boolean(errors.password)}
        errorMsg={errors.password?.message?.toString()}
        disabled={formState.isSubmitting}
      />

      <Button
        style={styles.button}
        mode="contained"
        onPress={(): void => {
          handleSubmit(submitHandler);
        }}
      >
        Login
      </Button>
    </View>
  );
};

export default LoginForm;

thanks will publish in the next release

thanks for testing, try this beta react-hook-form@3.23.19-beta.2

can you try this for now?

onPress={() => handleSubmit(onSubmit)}