Задать вопрос
@supfiger

Почему приходиться использовать асинхронность в React, чтобы добиться нужного результата?

Может, метод костыльный, но он работает.
Знаю, что this.state работает в react асинхронно, насколько я понимаю. Но вот я использую Mobx и у меня нет нигде this.state.

const textInput = useRef(null);

const editTodo = async () => {
 await onEditTodo(id);
 console.log("textInput.current", textInput.current);
};

// код

return (
  <input ref={textInput} />
);


Вот. в данном примере я использую Ref в самом компоненте (компонент у меня функциональный).
И при нажатии на кнопку у меня вызывается функция editTodo.
В консоли сейчас выводит нужный мне input, ref я повесил на него.
Консоль использую для наглядности, чтобы ошибки сразу не выскакивали в случае чего.

Но вот, без async await это не работает, в консоль выводить null.
Понимаю, что я что-то делаю не так.

Задача вообще у меня такая: в приложении при редактировании конкретного todo ставить фокус в данный input. По className'у бы взял, но тут же мне нужно фокус ставить в том Todo, на который я нажал.

Вот прилагаю скрин моего приложения:
5ede49b838591349139826.png

Возможно, есть метод более целесообразный устанавливать фокус на нужный input при нажатии кнопки?

Я использую: Mobx (store находится в отдельном файле).
  • Вопрос задан
  • 342 просмотра
Подписаться 1 Простой Комментировать
Решения вопроса 2
hzzzzl
@hzzzzl
потому что всё перерендеривается, и фокус теряется

можно решить подобным хаком, а вообще послушаю, будут ли другие варианты

setTimeout(() => {
   textInput.current.focus()
}, 0)   // сработает в следующем цикле event loop-a после рендера


По className'му бы взял, но тут же мне нужно фокус ставить в том Todo, на который я нажал

можно добавлять инпуту data- атрибут типа айдишника, и выбирать нужный как-то в духе document.querySelector('input[data-id="456"]')
Ответ написан
miraage
@miraage
Старый прогер
Набросал на коленке: https://codesandbox.io/s/todo-app-13njq?file=/src/...

Ну и основной файл, если лень по ссылке переходить.
import React from "react";

import "./TodoItem.css";

const Mode = {
  VIEW: "VIEW",
  EDIT: "EDIT"
};

export const TodoItem = ({ index, item, updateItem, removeItem }) => {
  const [mode, setMode] = React.useState(Mode.VIEW);
  const [input, setInput] = React.useState(item.text);
  const inputRef = React.useRef();

  React.useEffect(() => {
    if (mode === Mode.EDIT) {
      inputRef.current.focus();
    }
  }, [mode]);

  const handleInput = event => {
    setInput(event.target.value);
  };

  const saveItem = () => {
    updateItem(index, input);
    setMode(Mode.VIEW);
  };

  const handleToggleMode = () => {
    setMode(prevMode => (prevMode === Mode.VIEW ? Mode.EDIT : Mode.VIEW));
  };

  const handleRemove = () => {
    removeItem(index);
  };

  return (
    <div className="todo-item">
      <div className="todo-item__data">
        {mode === Mode.VIEW && (
          <div className="todo-item__value">{item.text}</div>
        )}
        {mode === Mode.EDIT && (
          <div className="todo-item__form">
            <input
              type="text"
              value={input}
              onChange={handleInput}
              ref={inputRef}
            />
            <button type="button" onClick={saveItem}>
              Save
            </button>
          </div>
        )}
      </div>
      <div className="todo-item__meta">
        <div className="todo-item__controls">
          <button type="button" onClick={handleToggleMode}>
            Edit
          </button>
          <button type="button" onClick={handleRemove}>
            Remove
          </button>
        </div>
        <div className="todo-item__time">{item.time.toLocaleString()}</div>
      </div>
    </div>
  );
};
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

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

Похожие вопросы