Как получить входное значение - PullRequest
0 голосов
/ 09 июля 2020

Я пытаюсь получить входное значение при нажатии такой кнопки:

Это переменная, которую я использую для хранения значения:

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('❌')
            }
        })
}, [])

Обычно каждый раз, когда я нажмите кнопку Я делаю запрос к хранилищу огня. В первый раз все работает нормально, но во второй раз, когда я нажимаю кнопку, я получаю сообщение об ошибке, в котором говорится, что textInput имеет значение null:

TypeError: null не является объектом (оценка 'textInput.current. value ')

Есть идеи?

Ответы [ 3 ]

2 голосов
/ 09 июля 2020

Проблема в том, что useCallback создает мемоизированный обратный вызов. И поскольку вы предоставили пустой массив зависимостей [], всегда будет возвращаться одна и та же функция.

В вашем случае это проблема c, потому что, используя createRef, вы создаете новую ссылку каждый раз, когда компонент повторный рендеринг.

Таким образом, ваш обратный вызов fetchRequest не знает о новом ref при повторном рендеринге компонента (предположительно, когда вы обновляете состояние с помощью setUsers() или setTitle()).

Решением здесь было бы либо:

  • Установить textInput как зависимость вашего useCallback, чтобы он знал о вновь созданном ref
const fetchRequest = useCallback(() => {
...
}, [textInput])

OR

  • используйте useRef вместо createRef, чтобы ссылка всегда была одинаковой, даже после повторного рендеринга.
2 голосов
/ 09 июля 2020

Похоже, это вызвано тем, что ссылка на входной элемент DOM теряется между отрисовками, а мемоизированный useCallback не помогает.

Вместо использования ref={textInput} вы должны использовать onBlur или onChange для обновления переменной состояния при изменении содержимого ввода. См. Документацию React по элементам формы. .

Это делает разделение лучше и гарантирует, что данные доступны с помощью функции обратного вызова, а не пытается получить доступ к узлу DOM и извлечение текущего значения.

Вы также, вероятно, не хотите использовать useCallback, просто сделайте это простой функцией. Это плохая привычка заранее оптимизировать использование мемоизации таким образом, поскольку дополнительная сложность может добавить ошибки (например, та, которую вы видите), но также, если она неправильно настроена, может возвращать устаревшую или неверную информацию.

Если вы не возражаете против того, чтобы данные устарели, и есть реальная проблема с производительностью, вы можете использовать это, но не забудьте включить переменную состояния номера телефона в конец массива зависимостей. См. Здесь документацию по правильному использованию .

1 голос
/ 11 июля 2020

Вероятно, вы захотите использовать перехватчик useRef (), тем более что он гарантированно сохраняется между рендерами, а не 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>
...