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

React中点击按钮获取输入值二次点击textInput为null的问题排查

解决React函数组件中第二次点击按钮时ref为null的问题

这个错误的根源很明确:你在**函数组件中错误地使用了React.createRef()**来获取DOM引用。

为什么会出现这个问题?

React.createRef()的特性是:每次组件重新渲染时,它都会生成一个全新的引用对象。当你点击按钮发起查询后,调用setUsers或setTitle会触发组件重新渲染,此时原来的textInput引用就不再指向输入框DOM元素了——第二次点击时,textInput.current自然就变成了null,也就会抛出TypeError: null is not an object的错误。

正确的解决方案:改用useRef()钩子

在函数组件中,管理DOM引用的正确方式是使用useRef()钩子,它会在组件的整个生命周期内保持同一个引用对象,不会因为组件重渲染而丢失指向。

下面是修改后的完整代码示例:

首先确保导入useRef:

import { useRef, useCallback, useState } from 'react';

替换ref的创建方式:

// 用useRef初始化,传入null作为初始值
const textInput = useRef(null);

输入框的ref绑定保持不变:

<input ref={textInput} type="tel" placeholder="Número de teléfono"></input>

优化后的点击回调(增加空判断和错误处理):

const fetchRequest = useCallback(() => {
  // 先检查输入框DOM是否存在,避免意外报错
  if (!textInput.current) return;
  
  const inputValue = textInput.current.value.trim();
  // 增加空输入判断,提升用户体验
  if (!inputValue) {
    setTitle('⚠️ 请输入有效的手机号');
    return;
  }

  database.collection('UsuariosDev').where('Telefono', '==', inputValue).get()
    .then(response => {
      const fetchedUsers = [];
      response.forEach(document => {
        const fetchedUser = { id: document.id, ...document.data() };
        fetchedUsers.push(fetchedUser);
        console.log(fetchedUser);
      });
      setUsers(fetchedUsers);
      // 简化标题设置逻辑
      setTitle(fetchedUsers.length > 0 ? '✔️' : '❌');
    })
    // 别忘了添加错误处理,避免查询失败时无反馈
    .catch(error => {
      console.error('查询用户数据失败:', error);
      setTitle('❌ 查询出错,请稍后重试');
    });
}, []); // useRef的引用本身不会变化,所以依赖数组为空即可

额外的优化方案:使用受控组件

如果你想更贴合React的单向数据流模式,也可以用useState来管理输入框的值,完全避免使用ref:

const [phoneNumber, setPhoneNumber] = useState('');
const [users, setUsers] = useState([]);
const [title, setTitle] = useState('');

const fetchRequest = useCallback(() => {
  const trimmedNumber = phoneNumber.trim();
  if (!trimmedNumber) {
    setTitle('⚠️ 请输入手机号');
    return;
  }

  database.collection('UsuariosDev').where('Telefono', '==', trimmedNumber).get()
    .then(response => {
      // ... 同之前的处理逻辑
    })
    .catch(error => {
      // ... 错误处理
    });
}, [phoneNumber]); // 依赖数组要加上phoneNumber,保证回调能获取最新值

对应的输入框改成受控组件:

<input 
  type="tel" 
  placeholder="Número de teléfono"
  value={phoneNumber}
  onChange={(e) => setPhoneNumber(e.target.value)}
/>

这种方式的优势是可以实时对输入值进行处理(比如格式化手机号),也更符合React的状态管理理念。

内容的提问来源于stack exchange,提问作者David Díaz

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 12:52:42