Kentavr16
@Kentavr16
long cold winter

Почему курсор переходит в начало строки в моем компоненте?

Создал компонент для просмотра/изменения записи, который вместо инпута использует элементы с contentEditable.
Компонент

type NoteEditorProps = {
  activeNote: Note | null;
  dispatch: Dispatch<Action>;
};

const NoteEditor = (props: NoteEditorProps) => {
  const [noteState, setNoteState] = useState<Partial<Note>>();
  const formatedLocalDateTime = useDatetimeInputDateFormat();
//хелпер, переводит дату в формат приемлемый для инпута
  const dateInputValue = noteState?.expiredAt
    ? formatedLocalDateTime(noteState.expiredAt)
    : formatedLocalDateTime(new Date());

  useEffect(() => {
//устанавливаю начальное состояние компонента
    if (props.activeNote !== null) {
      setNoteState(props.activeNote);
    }
  }, [props.activeNote]);

//собственно комплексный обработчик ввода для трех инпутов
  function inputsHandler(
    e: ChangeEvent<HTMLHeadingElement | HTMLParagraphElement | HTMLInputElement>
  ) {
    if (e.target.id === "expiredAt" && "value" in e.target) {
      setNoteState({ ...noteState, [e.target.id]: new Date(e.target.value) });
    } else if ("innerText" in e.target) {
      setNoteState({ ...noteState, [e.target.id]: e.target.innerText });
    }
  }

//гуард для проверки что все поля на месте при сабмите 
  function isNoteComplete(obj: Partial<Note> | undefined): obj is Note {
    return (
      obj?.noteName !== undefined &&
      obj?.noteText !== undefined &&
      obj?.expiredAt !== undefined &&
      obj?.createdAt !== undefined
    );
  }

//сабмит
  function handleNoteUpdate() {
    if (isNoteComplete(noteState)) {
      props.dispatch({
        type: "updateNote",
        payload: { updatedNote: noteState },
      });
    }
  }

  if (props.activeNote === null) {
    return (
      <div className="h-1/2 flex items-center justify-center">
        <p>
        Выберите запись для просмотра/редактирования.
        </p>
      </div>
    );
  }
  return (
    <div className="h-1/2 flex flex-col border-b-2 border-black">
      <h2
        className="text-2xl text-center font-bold my-2"
        contentEditable
        suppressContentEditableWarning={true}
        id="noteName"
        onInput={inputsHandler}
      >
        {noteState?.noteName}
      </h2>
      <p
        className="pl-4 m-6"
        contentEditable
        suppressContentEditableWarning={true}
        id="noteText"
        onInput={inputsHandler}
      >
        {noteState?.noteText}
      </p>
      <p className="m-2">
        Запись создана -  {noteState?.createdAt?.toLocaleString()}.
      </p>
      <div className="m-2">
        <CustomInput
          id="expiredAt"
          label="Дата напоминания"
          type="datetime-local"
          value={dateInputValue}
          onChange={inputsHandler}
        />
      </div>
      <CustomButton
        className="bg-green-300 rounded disabled:bg-gray-700 disabled:text-white  p-4 m-4 mr-6 self-end"
        disabledMessage="Все поля должны быть заполнены"
        onClick={handleNoteUpdate}
      >
        Подтвердить изменения записи.
      </CustomButton>
    </div>
  );
};

export default NoteEditor;



Прошу прощения за "простыню", специально ничего не убирал.
Собственно проблема - при вводе данных в элемент с contentEditable курсор после каждого ввода данных перескакивает в начало строки. Проблема известная, вот к примеру та же история, хоть и 6-летней давности вопрос.
Насколько я понял, проблема в изменении стейта и ререндерах. Окей. Я решил вопрос использованием рефов вместо стейта(костыли, откровенно говоря). Еще нормально работает, если повесить обработчик на onBlur вместо onInput.
Вопрос вот в чем - почему тогда в этом примере не происходит перескакивания курсора?
Есть ли аксакалы которые сталкивались с чем-то подобным?
  • Вопрос задан
  • 81 просмотр
Решения вопроса 1
Alexandroppolus
@Alexandroppolus
кодир
Зачем тебе эта содомия с contentEditable, если там по факту обычный текст без форматирования?? Сделай на православных инпутах, не морочь себе голову
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы