Ошибка преобразования компонента класса в функциональный компонент

#reactjs #react-hooks #react-functional-component #react-class-based-component

#reactjs #реагирующие крючки #реагирующий функциональный компонент #реагирующий компонент на основе класса

Вопрос:

Я пытаюсь преобразовать компонент класса в функциональный компонент.

Компонент класса: classBasedComponent.js [Исходный код, включенный в этот файл]

Прогресс, достигнутый мной:

Функциональный компонент: functionComponent.js [Мой прогресс]

Вот ссылка на GitHub для справки: https://github.com/codebushi/gatsby-starter-dimension

Вот мои ошибки:

  • 12:19 предупреждение «setArticle» присваивается значение, но никогда не используется no-unused-vars
  • 27:11 ошибка ‘timeoutId’ не определен no-undef
  • 33:6 предупреждение У useEffect с реактивным хуком отсутствует зависимость: ‘handleClickOutside’. Либо включите его, либо удалите массив зависимостей react-hooks / исчерпывающий-deps
  • 45:30 ошибка ‘setWrapperRef’ не определена no-undef
  • 58:37 Ожидаемое предупреждение ‘===’ и вместо этого увидел ‘==’ eqeqeq
  • 66:23 ошибка Неожиданного использования ‘location’ без ограничений-globals
  • 80:28 ошибка ‘setWrapperRef’ не определена no-undef

Я все еще получаю ошибки с этим. Где я могу импровизировать?

Ответ №1:

Давайте сосредоточимся на ошибках.

27:11 ошибка ‘timeoutId’ не определен no-undef

Вы объявили эту переменную как timeoutId , но переключаетесь между timeoutId и timeOutId при обращении к ней. В вашей текущей изолированной среде это так timeoutId , поэтому все timeOutId способы использования помечены как необъявленные. Остановитесь на одном или другом и будьте последовательны.

45:30 ошибка ‘setWrapperRef’ не определена no-undef

и

80:28 ошибка ‘setWrapperRef’ не определена no-undef

Похоже, это функция, вызываемая Main для передачи ссылки на что-то, на что затем ссылаются handleClickOutside . Используйте ref react для сохранения значения.

 const wrapperRef = React.useRef(null); // create ref to store value

...

const setWrapperRef = node => wrapperRef.current = node; // set current ref value

...

const handleClickOutside = (event) => {
  if (!wrapperRef.current.contains(event.target)) { // access current ref value
    if (isArticleVisible) {
      handleCloseArticle();
    }
  }
}

...

<Main
  isArticleVisible={isArticleVisible}
  timeout={timeout}
  articleTimeout={articleTimeout}
  article={article}
  onCloseArticle={handleCloseArticle}
  setWrapperRef={setWrapperRef} // attach ref value updater
/>
 

66:23 ошибка Неожиданного использования ‘location’ без ограничений-globals

location ранее был получен через props , вероятно, он все еще получен через props .

 <Layout location={props.location}>
 

Или, поскольку я не вижу других ссылок props на ваш функциональный компонент, просто уничтожьте его в подписи компонента. Если вам нужно получить доступ к большему количеству значений prop, вы можете просто также уничтожить их здесь.

 function IndexPage({ location }) { ...
 

И теперь предупреждения

12:19 предупреждение «setArticle» присваивается значение, но никогда не используется no-unused-vars

Это просто означает, что он был определен и никогда не использовался, но после проверки компонента на основе класса обновление article значения происходит в handleOpenArticle и handleCloseArticle . Итак, давайте сделаем то же самое в вашем функциональном компоненте.

Проблема здесь заключалась в том, что вы передавали setIsArticleVisible программе обновления дополнительные аргументы, которые игнорировались. useState программы обновления не объединяют обновления неглубоко, а ваши объявлены содержащими только одно значение. Я предлагаю также использовать обновление функционального состояния для переключения значений логического состояния.

 handleOpenArticle(article) {
  this.setState({
    isArticleVisible: !this.state.isArticleVisible,
    article
  });

  setTimeout(() => {
    this.setState({
      timeout: !this.state.timeout
    });
  }, 325);

  setTimeout(() => {
    this.setState({
      articleTimeout: !this.state.articleTimeout
    });
  }, 350);
}

handleCloseArticle() {
  this.setState({
    articleTimeout: !this.state.articleTimeout
  });

  setTimeout(() => {
    this.setState({
      timeout: !this.state.timeout
    });
  }, 325);

  setTimeout(() => {
    this.setState({
      isArticleVisible: !this.state.isArticleVisible,
      article: ""
    });
  }, 350);
}
 

становится

 const handleOpenArticle = (article) => {
  setIsArticleVisible(isArticleVisible => !isArticleVisible);
  setArticle(article);
  setTimeout(() => setTimeout(timeout => !timeout), 325);
  setTimeout(() => setArticleTimeout(articleTimeout => !articleTimeout), 350);
};

const handleCloseArticle = (article) => {
  setArticleTimeout(articleTimeout => !articleTimeout);
  setTimeout(() => setTimeout(timeout => !timeout), 325);
  setTimeout(() => {
    setIsArticleVisible(isArticleVisible => !isArticleVisible);
    setArticle("");
  }, 350);
};
 

33:6 предупреждение О том, что useEffect реагирует на хук, имеет отсутствующую зависимость:
‘handleClickOutside’. Либо включите его, либо удалите массив зависимостей
react-hooks / исчерпывающий-deps

Обычно вы хотели бы включить все зависимости для эффекта, чтобы все значения были правильными, но здесь ясно, что намерение состоит в том, чтобы добавить слушателей при монтировании компонента и удалить их при размонтировании. Вы можете добавить eslint-disable комментарий только для этой строки. Я предлагаю также переместить timeoutId timeOutId объявление / внутри эффекта, поскольку оно не используется вне его. Также безопасно переходить undefined к clearTimeout нему, он может справиться с этим, поэтому удалите условную проверку.

 useEffect(() => {
  const timeoutId = setTimeout(() => {
    setLoading("");
  }, 100);

  document.addEventListener("mousedown", handleClickOutside);

  return () => {
    clearTimeout(timeoutId);
    document.removeEventListener("mousedown", handleClickOutside);
  };
  // Effect triggered on component mount only
  // eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
 

58:37 Ожидаемое предупреждение ‘===’ и вместо этого увидел ‘==’ eqeqeq

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

Примечание:

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

Комментарии:

1. Я получаю последующую ошибку: ошибка: превышена максимальная глубина обновления. Это может произойти, когда компонент повторно вызывает setState внутри componentWillUpdate или componentDidUpdate . React ограничивает количество вложенных обновлений, чтобы предотвратить бесконечные циклы. Эта ошибка, по-видимому, вызвана эффектом использования.

2. Я использую article в качестве опоры. Я использую кнопку с кодом: <кнопка onClick={props.onOpenArticle(‘id’)}>Работает</button> в другом файле. Это вызывает бесконечные циклы.

3. @KillMe Есть ли у этой новой ошибки трассировка стека? Можете ли вы сказать, какой компонент вызывает ошибку? В IndexPage компоненте в вашем codesandbox состояние useEffect не устанавливается безоговорочно и не имеет зависимостей, поэтому оно не будет повторно запускаться при последующих рендерингах.

4. @KillMe Ах, можете ли вы тогда поделиться этим другим файлом и деталями ошибки в своем вопросе?

5. Вот файл: codesandbox.io/s/dreamy-flower-1vkuc?file=/src/header.js