Прослушивание события значения по умолчанию useState - PullRequest
0 голосов
/ 02 ноября 2019

Я хотел бы знать, как получить обновленный labelRef внутри функции, а именно: inputBlur()

import React, { useState, useRef, useEffect } from "react";
import ReactDOM from "react-dom";

import "./styles.css";

function App() {
  const [inputValue, setInputValue] = useState("Type...");
  const [labelWidth, setLabelWidth] = useState();
  const labelRef = useRef();

  const inputChange = e => {
    setInputValue(e.target.value);
    setLabelWidth(labelRef.current.offsetWidth);
  };

  const inputBlur = e => {
    const trimmed = e.target.value.trim();
    if (trimmed) {
      setInputValue(trimmed);
    } else {
      setInputValue("Type...");
    }
    setLabelWidth(labelRef.current.offsetWidth);
  };

  useEffect(() => {
    setLabelWidth(labelRef.current.offsetWidth);
  }, []);
  return (
    <div className="App">
      <p>Type below to see if input and div is the same width</p>
      <div ref={labelRef}>{inputValue}</div>
      <br />
      <input
        value={inputValue}
        onChange={e => inputChange(e)}
        onBlur={e => inputBlur(e)}
        style={{ width: `${labelWidth}px` }}
      />
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Чтобы объяснить этот пример немного, есть поле ввода, которое меняет свою ширину назаполнение div тем же текстом. В настоящее время, это не работает правильно, когда поле ввода пусто, сопровождаемое событием onblur. Поле ввода должно быть заполнено значением по умолчанию useState, "Type...", но ширина поля ввода равна 0.

Я вижу проблему в том, что в функции inputBlur после запуска setInputValue,строка labelRef.current.offsetWidth по-прежнему отражает старый элемент, поскольку он еще не визуализировал этот элемент.

Здесь приведена ссылка на codesandbox этого примера, чтобы попытаться воспроизвести эту проблему.

Моя проблема возникла из-за непонимания потока реакции. Мне нужно захватить событие после того, как useState обновил элемент со значением по умолчанию, а затем вычислил ширину.

Примечание: я не хочу, чтобы ввод автоматически заполнял пустое поле ввода значением по умолчаниюЗначение пока в фокусе. Он должен быть заполнен в случае onBlur().

Ответы [ 2 ]

1 голос
/ 02 ноября 2019

Не совсем уверен, правильно ли я понял ваш вопрос, поэтому это похоже на предположение.

Основная причина: вы вызываете и setInputValue, и setLabelWidth в одном месте - обработчик ввода. Но setInputValue обновит метку новым значением только при следующем рендере. Таким образом, для предыдущего значения требуется labelWidth.

Это происходит не только при очистке значения - вы можете видеть, что ширина ввода непостоянно изменяется при вводе.

Разделяйте его useEffect:

  const inputBlur = e => {
    const trimmed = e.target.value;
    if (trimmed) {
      setInputValue(trimmed);
    } else {
      setInputValue("Type...");
    }
  };

  useEffect(() => {
    setLabelWidth(labelRef.current.offsetWidth);
  }, [inputValue])
0 голосов
/ 02 ноября 2019

в функции inBlur, вы обновляете labeWidth текущим значением offsetWidth div, которое всегда равно 0 после пустого ввода, за которым следует событие onBlur. Измените это на: setLabelWidth(labelWidth);

Другой способ заключается в перемещении ref={labelRef} к элементу ввода: <input ref={labelRef} />. Смотрите официальные документы

...