You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

单组件使用两个React Hook Form时登录输入框无法输入

问题

我尝试在一个卡片内通过切换开关实现注册与登录表单,为此声明了两个独立的useForm()实例。注册表单可正常输入、验证并提交数据,但登录表单的输入框无法输入内容。我已重命名第二个useForm实例的大部分props,请问问题出在哪里?

注册表单代码

const {control, handleSubmit, formState: { errors }, reset, getValues} = useForm({
    resolver: yupResolver(validatorSchema),

    defaultValues: {
      'username':"",
      'email':'',
      'password':'',
      'confirmPassword':''
    }, mode:'onBlur'
  })

  const [addUser, {loading, error}] =  useMutation(REGISTER_USER, {
    update (proxy, result) {
      console.log(result)
      navigate('/home')
    },
    variables: {
      username: getValues("username"),
      email: getValues("email"),
      password: getValues("password"),
      role: dropdown
    }
  })

  const submit = (data) => {
    console.log(data)
    addUser()
    reset()
  }

登录表单代码

const {control: authControl, handleSubmit: onSubmit, reset: res, formState: { errors: errors2 },getValues: getAuthValues} = useForm({
    resolver: yupResolver(loginValidatorSchema),

    defaultValues: {
      'loginUsername': "",
      'loginPassword': ""
    },
    mode: 'all'
  })

  isSignup ? console.log(errors) : console.log(errors2)

  const [loginUser] = useMutation(AUTHENTICATE_USER,{
    update(_,result) {
      navigate('/home')
    },

    variables: {
      username: getAuthValues('loginUsername'),
      password: getAuthValues('loginPassword')  
    }
  })

  const authSubmit = (data) => {
    console.log(data)
    loginUser()
    res()
  }

组件渲染代码

const element = <TextInput.Icon name="lock-outline" />
  return (
    <SafeAreaView>
      <ScrollView contentContainerStyle={Styles.container}>
        <Image
          style={
            Styles.image
          }
          source={assets.kotaco}
        />

      
      <Card containerStyle={{
        borderRadius: "20px",
        overflow: "hidden"
      }}>
      
      <Card.Title style={{color: '#dc1846'}}>{isSignup?'Sign up': 'Sign in'}</Card.Title>
            
      <View style={{
        marginLeft: "250px",
        overflow: "hidden"
      }}>
      <Switch
      
      onValueChange={toggleSwitch}
      value={isSignup}
      />
      </View>

      {
        isSignup ?
        <View>
        <Controller 
        control={control}
        name="username"
        render={({field: {onChange, value, onBlur}}) => (
            <TextInput
                placeholder=' username'
                style={Styles.input}
                value={value}
                
                //left={<TextInput.Icon name="alert-circle" size={20} color={'red'} />}
                left={element}
                onBlur={onBlur}
                onChangeText={(value) => onChange(value)}
                autoFocus half
            />
            )}
        />
        <Controller 
        control={control}
        name="email"
        render={({field: {onChange, value, onBlur}}) => (
            <TextInput
                placeholder=' email'
                style={Styles.input}
                value={value}
                onBlur={onBlur}
                keyboardType='email-address'
                onChangeText={(value) => onChange(value)}
                autoFocus half
            />
            )}
        />
       

      <Controller 
        control={control}
        name="password"
        render={({field:{onChange, value, onBlur}}) => (
            <TextInput
                placeholder=' password'
                style={Styles.input}
                value={value}
                onBlur={onBlur}
                secureTextEntry={showPassword}
                right={<TextInput.Icon name={showPassword ? "eye" : "eye-off"} onPress={() => setShowPassword(!showPassword)} />}
                onChangeText={(value) => onChange(value)}
                autoFocus half
            />
            )}
        />
      
      <Controller 
        control={control}
        name="confirmPassword"
        render={({field:{onChange, value, onBlur}}) => (
            <TextInput
                placeholder=' confirm password'
                style={Styles.input}
                value={value}
                type='password'
                onBlur={onBlur}
                secureTextEntry={showPassword}
                onChangeText={(value) => onChange(value)}
                autoFocus half
            />
            )}
        />
       

      <View style={{flexDirection:"row", marginTop: 10, marginBottom: 10}}>
      
      <Button 
        title="Sign up" 
        type="solid" 
        titleStyle={{ fontWeight: '700' }}
        buttonStyle={{
          backgroundColor: "rgba(199, 43, 98, 1)",
          borderColor: 'transparent',
          borderWidth: 0,
          borderRadius: 30,
        }}
        containerStyle={{
          width: 100,
          marginRight: 50
        }}
        onPress={ handleSubmit(submit)}
        />

      <Dropdown 
      style={Styles.dropdown}
      iconStyle={Styles.icon}
      data={roles}
      labelField="label"
      valueField="value"
      placeholder=" Select a role"
      value={dropdown}
      onChange={item => setDropdown(item.value)}
      renderLeftIcon={() => (
        <Icon
          style={Styles.icon}
          color="#fc2d79"
          name="person-circle-outline"
          size={20}
        />
      )}
      />
      </View>
        </View>

          :

      <View>
        <Controller 
        control={authControl}
        name="loginUsername"
        render={({field:{onChange, value, onBlur}}) => (
            <TextInput
                placeholder=' username'
                style={Styles.input}
                value={value}
                onBlur={onBlur}
                onChangeText={(value) => onChange(value)}
                autoFocus half
            />
            )}
        />

        <Controller 
        control={authControl}
        name="loginPassword"
        render={({field:{onChange, value, onBlur}}) => (
            <TextInput
                placeholder=' password'
                style={Styles.input}
                value={value}
                type='password'
                onBlur={onBlur}
                secureTextEntry={showPassword}
                onChangeText={(value) => onChange(value)}
                autoFocus half
            />
            )}
        />
      
      <View style={{alignSelf:'center',marginTop: 15, marginBottom: 15}}>
      
      <Button 
        title="Sign in" 
        type="solid" 
        titleStyle={{ fontWeight: '700' }}
        buttonStyle={{
          backgroundColor: "rgba(199, 43, 98, 1)",
          borderColor: 'transparent',
          borderWidth: 0,
          borderRadius: 30,
          
        }}
        containerStyle={{
          width: 100,
          //marginRight: 50,
          
        }}
        onPress={onSubmit(authSubmit)}
        />
      </View>

        </View>
      }

      </Card>
      
      </ScrollView>
    </SafeAreaView>
  )
}
问题分析与解决方案

核心问题1:useMutation变量初始化时机错误

登录表单的useMutation在初始化时直接通过getAuthValues获取表单值,这只会在组件首次渲染时执行一次,后续输入内容不会更新variables的值。而且该写法会在组件初始化时就调用getAuthValues,此时表单值都是默认空值,后续输入也无法触发变量更新,直接导致登录逻辑异常,同时干扰表单输入状态。

修复方式:将变量传递移到loginUser调用时,利用authSubmit接收的表单数据传入:

const [loginUser] = useMutation(AUTHENTICATE_USER,{
  update(_,result) {
    navigate('/home')
  }
})

const authSubmit = (data) => {
  console.log(data)
  // 调用时传入最新的表单数据
  loginUser({
    variables: {
      username: data.loginUsername,
      password: data.loginPassword  
    }
  })
  res()
}

核心问题2:登录按钮的onPress绑定错误

登录按钮的onPress={onSubmit(authSubmit)}会在组件渲染时立即执行onSubmit(authSubmit),而非点击按钮时执行。这会导致表单被立即提交,同时破坏表单的输入状态绑定,直接表现为输入框无法输入。

修复方式:用箭头函数包裹,延迟执行提交逻辑:

<Button 
  title="Sign in" 
  type="solid" 
  titleStyle={{ fontWeight: '700' }}
  buttonStyle={{
    backgroundColor: "rgba(199, 43, 98, 1)",
    borderColor: 'transparent',
    borderWidth: 0,
    borderRadius: 30,
  }}
  containerStyle={{
    width: 100,
  }}
  onPress={() => onSubmit(authSubmit)()}
/>

额外优化:修复注册表单的同类问题

注册表单的useMutation也存在相同的变量初始化时机问题,建议同步修复:

const [addUser, {loading, error}] =  useMutation(REGISTER_USER, {
  update (proxy, result) {
    console.log(result)
    navigate('/home')
  }
})

const submit = (data) => {
  console.log(data)
  addUser({
    variables: {
      username: data.username,
      email: data.email,
      password: data.password,
      role: dropdown
    }
  })
  reset()
}

内容的提问来源于stack exchange,提问作者22nd_wallflower

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 09:46:06