Не удается выполнить обновление состояния реагирования для неустановленного дочернего компонента? - PullRequest
0 голосов
/ 01 апреля 2020

Получаю это предупреждение:

Невозможно выполнить обновление состояния React для отключенного компонента. Это неоперация ...

Это результат child component, и я не могу понять, как сделать это go.

Обратите внимание, что Я прочитал много других сообщений о том, почему это происходит, и понимаю основную проблему c. Тем не менее, большинство решений предлагают отменить подписки в функции стиля componentWillUnmount (я использую react hooks)

Я не знаю, указывает ли это на какое-то большее фундаментальное недоразумение, которое у меня есть в React, но вот по сути то, что у меня есть:

import React, { useEffect, useRef } from 'react';
import Picker from 'emoji-picker-react';

const MyTextarea = (props) => {

  const onClick = (event, emojiObject) => {
    //do stuff...
  }

  const isMountedRef = useRef(true);

  useEffect(() => {
    isMountedRef.current = true;
  });

  useEffect(() => {
    return () => {
      console.log('will unmount');
      isMountedRef.current = false;
    }
  });

  return (
    <div>
      <textarea></textarea>
      { isMountedRef.current ? (
          <Picker onEmojiClick={onClick}/>
        ):null
      }
    </div>
  );
};

export default MyTextarea;

(tl; dr) Обратите внимание:

  • MyTextarea имеет компонент parent , который отображается только на определенном маршруте.

  • Theres также компонент Menu, который после нажатия изменяет route и в зависимости от ситуации либо покажет MyTextarea '* родительский компонент или показать другой компонент.

  • Это предупреждение появляется, когда я нажимаю Menu, чтобы отключить MyTextarea родительский компонент.

Больше контекста

  • Другие ответы на StackOverflow предлагают внести изменения, чтобы предотвратить state обновления, когда компонент не смонтирован. В моей ситуации я не могу этого сделать, потому что я не проектировал компонент Picker (визуализированный MyTextarea). Предупреждение происходит от из этой строки <Picker onEmojiClick={onClick}>, но я не хотел бы изменять этот готовый компонент.

  • Это объясняет мою попытку визуализировать компонент или не основываться на isMountedRef. Однако это тоже не работает. Что происходит, так это то, что компонент либо визуализируется, если я установил useRef(true), либо он вообще не отображается, если я установил useRef(null), как предлагали многие.

1 Ответ

1 голос
/ 01 апреля 2020

Я не совсем уверен, в чем ваша проблема на самом деле (это то, что вы не можете избавиться от предупреждения или что <Picker> всегда рендерится или никогда не будет), но я постараюсь решить все проблемы, которые я вижу.

Во-первых, вам не нужно условно отображать <Picker> в зависимости от того, смонтирован ли MyTextArea или нет. Поскольку компоненты отображаются только после монтирования, <Picker> никогда не будет отображаться, если компонент, в котором он находится, не был подключен.

При этом, если вы все еще хотите отслеживать, когда компонент монтируется, я рекомендую не использовать хуки и вместо них использовать componentDidMount и componentWillUnmount с setState(). Это не только облегчит понимание жизненного цикла вашего компонента, но также есть некоторые проблемы с тем, как вы используете хуки.

Сейчас ваш useRef(true) установит isMountedRef.current в true когда компонент инициализирован, так что это будет верно даже до его монтирования. useRef() - это не то же самое, что componentDidMount().

Использование 'useEffect ()' для переключения isMountedRef.current в true, когда компонент смонтирован, также не будет работать. Хотя он будет срабатывать при монтировании компонента, useEffect() предназначен для побочных эффектов, а не обновлений состояния, поэтому он не запускает повторную визуализацию, поэтому компонент никогда не рендерится при установке useRef(null).

Кроме того, ваша ловушка useEffect() будет срабатывать при каждом обновлении компонента, а не только при его монтировании, а функция очистки (возвращаемая функция) также будет запускаться при каждом обновлении, а не только при размонтировании. Таким образом, при каждом обновлении isMountedRef.current будет переключаться с true на false и обратно на true. Тем не менее, ничего из этого не имеет значения, потому что компонент все равно не будет повторно визуализироваться (как объяснено выше).

Если вам действительно нужно использовать useEffect(), тогда вы должны объединить его в одну функцию и использовать его для Обновите состояние, чтобы запустить повторную визуализацию:

const [isMounted, setIsMounted] = useState(false);  // Create state variables

useEffect(() => {
  setIsMounted(true);  // The effect and clean up are in one function
  return () => {
    console.log('will unmount');
    setIsMounted(false);
  }
}, [] // This prevents firing on every update, w/o it you'll get an infinite loop
);

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

Редактировать: Кажется, что предупреждение вызвано вашим пакетом комплектовщика, и для него уже есть проблема https://github.com/ealush/emoji-picker-react/issues/142

...