Ошибка пользовательского перехвата: перехваты могут вызываться только внутри тела компонента функции - PullRequest
0 голосов
/ 28 сентября 2019

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

Uncaught Invariant Violation: Invalid hook call.Хуки могут быть вызваны только внутри тела функционального компонента.Это может произойти по одной из следующих причин:

  1. У вас могут быть несовпадающие версии React и средства визуализации (например, React DOM)
  2. Возможно, вы нарушаете правила хуков
  3. У вас может быть несколько копий React в одном приложении

Это мой хук:

import React, { useState, useEffect } from 'react';

const useInfiniteScroll = (isLastPage: boolean, fetchFn: any) => {
  const [pageCount, setPageCount] = useState(0);
  const triggerFetchEvents = (): void => {
    let response;

    setPageCount(() => {
      if (!isLastPage) {
        response = fetchFn(pageCount + 1, 5, 'latest');
      }

      return pageCount + 1;
    });

    return response;
  };

  useEffect(() => {
    triggerFetchEvents();
  }, []);

  return pageCount;
};

export default useInfiniteScroll;

И вот этот компонент явызывая его:

import React, { FC } from 'react';
import { connect } from 'react-redux';
import { fetchEvents } from '../../shared/actions/eventActions';
import { AppState } from '../../shared/types/genericTypes';
import EventModel from '../../shared/models/Event.model';
import EventListPage from '../../components/events/EventListPage';
import useInfiniteScroll from '../../shared/services/triggerInfiniteScroll';

type Props = {
  fetchEvents?: any;
  isLastPage: boolean;
  eventsList?: EventModel[];
};

const mapState: any = (state: AppState, props: Props): Props => ({
  eventsList: state.eventReducers.eventsList,
  isLastPage: state.eventReducers.isLastPage,
  ...props
});

const actionCreators = {
  fetchEvents
};

export const EventsScene: FC<Props> = props => {
  const { eventsList, fetchEvents, isLastPage } = props;
  const useIn = () => useInfiniteScroll(isLastPage, fetchEvents);

  useIn();

  // const [pageCount, setPageCount] = useState(0);

  // const triggerFetchEvents = (): void => {
  //   let response;

  //   setPageCount(() => {
  //     if (!isLastPage) {
  //       response = fetchEvents(pageCount + 1, 1, 'latest');
  //     }

  //     return pageCount + 1;
  //   });

  //   return response;
  // };

  // useEffect(() => {
  //   triggerFetchEvents();
  // }, []);

  if (!eventsList || !eventsList.length) return null;

  return (
    <EventListPage
      eventsList={eventsList}
      isLastPage={isLastPage}
      triggerFetchEvents={useIn}
    />
  );
};

export default connect(
  mapState,
  actionCreators
)(EventsScene);

Я оставил закомментированный код там, чтобы показать вам, что если я раскомментирую код и удалю useInfiniteScroll, то он будет работать правильно.

Чего мне не хватает?

ОБНОВЛЕНИЕ: Это EventListPage компонент

import React, { useState, useEffect } from 'react';
import { Link } from 'react-router-dom';
import EventModel from '../../shared/models/Event.model';
import { formatDate } from '../../shared/services/date';
import Container from 'react-bootstrap/Container';
import Row from 'react-bootstrap/Row';
import Col from 'react-bootstrap/Col';
import Card from 'react-bootstrap/Card';

type Props = {
  eventsList?: EventModel[];
  isLastPage: boolean;
  triggerFetchEvents: any;
};

export const EventListPage: React.FC<Props> = props => {
  const { eventsList, triggerFetchEvents, isLastPage } = props;

  const [isFetching, setIsFetching] = useState(false);

  const fetchMoreEvents = (): Promise<void> =>
    triggerFetchEvents().then(() => {
      setIsFetching(false);
    });

  const handleScroll = (): void => {
    if (
      document.documentElement.offsetHeight -
        (window.innerHeight + document.documentElement.scrollTop) >
        1 ||
      isFetching
    ) {
      return;
    }

    return setIsFetching(true);
  };

  useEffect(() => {
    if (isFetching) return;

    window.addEventListener('scroll', handleScroll);

    return () => {
      window.removeEventListener('scroll', handleScroll);
    };
  }, []);

  useEffect(() => {
    if (!isFetching) return;

    if (!isLastPage) fetchMoreEvents();
  }, [isFetching]);

  if (!eventsList) return null;

  return (
    <Container className='article-list mt-5'>
      ///...
    </Container>
  );
};

export default EventListPage;

1 Ответ

0 голосов
/ 28 сентября 2019

В EventsScene, измените useInfiniteScroll, чтобы он вызывался непосредственно на верхнем уровне тела функции (не уверен, зачем вы сначала создаете это косвенное указание):

// before
const useIn = () => useInfiniteScroll(isLastPage, fetchEvents);
useIn();

// after
useInfiniteScroll(isLastPage, fetchEvents)

Реакция ожидает Hookвызовы только происходят на верхнем уровне , поскольку порядок хуков зависит от того, чтобы они всегда были одинаковыми.Если вы заключите хук в функцию, вы можете потенциально вызывать эту функцию во многих местах кода, нарушающих порядок хуков.

Существует внутренний список «ячеек памяти», связанных с каждым компонентом.Это просто объекты JavaScript, куда мы можем поместить некоторые данные.Когда вы вызываете Hook, например, useState (), он читает текущую ячейку (или инициализирует ее во время первого рендеринга), а затем перемещает указатель на следующий.Вот как несколько вызовов useState () каждый получает независимое локальное состояние. Ссылка

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...