开发者问题收集

如何获取输入值

2020-07-09
100

我试图在单击按钮时获取输入值,如下所示:

这是我用来存储值的变量:

let textInput = React.createRef();

这是我执行的方式:

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

然后,我有一个按钮:

<button onClick={fetchRequest} className="btn btn-default">Comprobar teléfono</button>

它调用这个:

const fetchRequest = useCallback(() => {
    database.collection('UsuariosDev').where('Telefono', '==', 
      textInput.current.value).get()
        .then(response => {
            const fetchedUsers = [];
            response.forEach(document => {
                const fetchedUser = {
                    id: document.id,
                    ...document.data()
                };
                fetchedUsers.push(fetchedUser);
                console.log(fetchedUser)
            });
            setUsers(fetchedUsers);
            if (fetchedUsers.length !== 0) {
                setTitle('✔️')
            } else {
                setTitle('❌')
            }
        })
}, [])

基本上每次我单击按钮时,我都会进行一次 Firestore 查询。第一次它工作正常,但第二次单击按钮时出现错误,提示 textInput 为空:

TypeError: null is not an object (evaluating 'textInput.current.value')

有什么想法吗?

3个回答

这里的问题是 useCallback 创建了一个记忆回调。而且由于您提供了一个空的依赖项数组 [] ,因此将始终返回相同的函数。

对于您而言,这是有问题的,因为通过使用 createRef ,每次组件重新渲染时,您都会创建一个新的 ref。

因此,当组件重新渲染时(大概是当您使用 setUsers()setTitle() 更新状态时),您的 fetchRequest 回调并不知道新的 ref。

这里的解决方案可以是:

  • textInput 设置为 useCallback 的依赖项,以便它知道新创建的 ref
const fetchRequest = useCallback(() => {
...
}, [textInput])

  • 使用 useRef 而不是 createRef ,这样 ref 就始终相同,即使在重新渲染之后也是如此。
Neeko
2020-07-09

这似乎是由于对输入 DOM 元素的引用在渲染之间丢失而导致的,而记忆化的 useCallback 没有帮助。


当输入的内容发生变化时,您应该使用 onBluronChange 来更新状态变量,而不是使用 ref={textInput 查看有关表单元素的 React 文档

这使得分离更加清晰,并确保数据可通过回调函数访问,而不是尝试访问 DOM 节点并提取其当前值。


您可能也不想使用 useCallback ,只需将其作为一个简单的函数即可。 以这种方式使用记忆化进行早期优化是一种坏习惯,因为增加的复杂性可能会增加错误(例如您看到的错误),而且如果设置不正确,还可能返回过时或不正确的信息。

如果您不介意数据变得陈旧,并且存在真正的性能问题,那么您可以使用它,但请记住在最后将电话号码状态变量包含在依赖项数组中。 有关正确用法的文档,请参阅此处

Luke Storry
2020-07-09

您可能想要使用 useRef() Hook,特别是因为它保证在渲染之间保留,而不是 createRef() - 我经常这样做。

同样,作为一种良好的设计实践,我 认为 您想将电话输入和按钮点击分离 - 我会利用 useState() 钩子来更新该输入的电话号码 onChange(),并在获取中引用状态值 - 类似于(警告:未经测试的代码)

const [ telephone, setTelephone] = useState("");

const UpdateUsers = () => {
    database.collection('UsuariosDev')
    .where('Telefono', '==', telephone)
    .get()
    .then(response => {
        const fetchedUsers = [];
        response.forEach(document => {
            const fetchedUser = {
                ...document.data(),
                id: document.id
            };
            fetchedUsers.push(fetchedUser);
            console.log(fetchedUser)
        });
        setUsers(fetchedUsers);
        if (fetchedUsers.length !== 0) {
            setTitle('✔️')
        } else {
            setTitle('❌')
        }
    })
};

<input
  onchange={e => setTelephone(e.target.val())}
  type="tel"
  placeholder="Número de teléfono"
/>

<button
  onClick={UpdateUsers}
  className="btn btn-default">
  Comprobar teléfono
</button>
LeadDreamer
2020-07-10