0

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

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

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 不是对象(评估'textInput.current.value')

有任何想法吗?

4

3 回答 3

2

看起来这是由于在渲染之间丢失了对输入 DOM 元素的引用,并且 memoiseduseCallback没有帮助。


当输入的内容发生变化时ref={textInput},您应该使用onBluror来更新状态变量,而不是使用。请参阅有关表单元素的 React 文档onChange

这样可以更好地分离,并确保回调函数可以访问数据,而不是尝试访问 DOM 节点并提取其当前值。


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

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

于 2020-07-09T12:36:26.547 回答
2

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

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

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

这里的解决方案是:

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

或者

  • 使用useRef而不是createRef这样 ref 始终相同,即使在重新渲染之后也是如此。
于 2020-07-09T13:22:55.707 回答
1

您可能想要使用 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>
于 2020-07-10T21:08:05.050 回答