React Hooks: значение старого состояния сохраняется в закрытии - PullRequest
1 голос
/ 08 марта 2019

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

Итак, я пытаюсь создать компонент ввода тегов, в который вы вводите текст, и всякий раз, когда вы вводите пробел, он добавляет эту строку в список, который вы передаете. Чтобы удалить один из тегов, вы Очистите область редактирования содержимого, нажмите клавишу Backspace один раз, чтобы «подготовить» последний тег в списке для удаления, а затем снова, чтобы подтвердить удаление. Это имеет смысл в контексте, но я написал сокращенную версию для примера. У меня есть следующие коды andbox: https://codesandbox.io/s/8q0q3qw60

Теперь вот часть, которую я не понимаю.

Кажется, что все работает полностью так, как задумано, за исключением фактического удаления тега. По какой-то причине я могу соответствующим образом "подготовить" последний тег для удаления, однако, когда я снова нажимаю клавишу Backspace, чтобы подтвердить, по какой-то причине состояние (из ловушки) для prepTagForRemoval в закрытии, которое является обратным вызовом keyDown для содержимого редактируемая область никогда не изменяется . Это всегда ложь, но только внутри обратного вызова ! Это приводит к тому, что тег никогда не удаляется надлежащим образом после подтверждения его удаления.

Чтобы повторить это ...

  1. открыть код песочницы ссылка
  2. нажмите на красную рамку (div-редактируемый контент)
  3. введите "привет" (без кавычек, поэтому привет, затем пробел
  4. привет переместится на строку выше с надписью «Метки:»
  5. нажмите клавишу Backspace один раз
  6. Заготовка для удаления теперь верна, и «привет» подсвечивается красным
  7. снова нажмите клавишу Backspace

В настоящее время на этом этапе должен только что удалить "hello" из строки "Tags:", однако в действительности он просто устанавливает prepForRemoval в false и снова делает hello black, без удаления "привет" из "Метки:"

Извините, если это сбивает с толку, я рад попытаться уточнить больше. Я действительно хочу, чтобы этот пример работал правильно и удалял последний тег (или, по крайней мере, вызывал onRemove) при повторном удалении. Надеюсь, кто-то может протянуть руку!

1 Ответ

2 голосов
/ 08 марта 2019

Это ошибка в реагирующем контенте .Ниже приведен метод shouldComponentUpdate.Он не проверяет изменение на onKeyDown и, поскольку backspace не вызывает изменений в значении, он не будет повторно отображаться, поэтому он использует устаревшую версию вашей функции handleKeyDown.

  shouldComponentUpdate(nextProps: Props): boolean {
    const { props } = this;
    const el = this.getEl();

    // We need not rerender if the change of props simply reflects the user's edits.
    // Rerendering in this case would make the cursor/caret jump

    // Rerender if there is no element yet... (somehow?)
    if (!el) return true;

    // ...or if html really changed... (programmatically, not by user edit)
    if (
      normalizeHtml(nextProps.html) !== normalizeHtml(el.innerHTML)
    ) {
      return true;
    }

    // Handle additional properties
    return props.disabled !== nextProps.disabled ||
      props.tagName !== nextProps.tagName ||
      props.className !== nextProps.className ||
      props.innerRef !== nextProps.innerRef ||
      !deepEqual(props.style, nextProps.style);
  }

Здесь он работает с фиксированной копией реагировать-contenteditable: https://codesandbox.io/s/o41yjr3r3q

Я изменил последнюю часть shouldComponentUpdate, добавив props.onKeyDown !== nextProps.onKeyDown:

return (
  props.disabled !== nextProps.disabled ||
  props.tagName !== nextProps.tagName ||
  props.className !== nextProps.className ||
  props.innerRef !== nextProps.innerRef ||
  props.onKeyDown !== nextProps.onKeyDown ||
  !deepEqual(props.style, nextProps.style)
);
...