Javascript 自定义钩子错误:钩子只能在函数组件的主体内部调用

Javascript 自定义钩子错误:钩子只能在函数组件的主体内部调用,javascript,reactjs,typescript,ecmascript-6,Javascript,Reactjs,Typescript,Ecmascript 6,我试图开发一个定制的钩子,这似乎很容易,但我得到了一个错误 未捕获不变冲突:钩子调用无效。钩子只能在函数组件的主体内部调用。这可能是由于以下原因之一: React和渲染器的版本可能不匹配(例如React DOM) 你可能违反了钩子的规则 同一应用程序中可能有多个React副本 这是我的钩子: import React, { useState, useEffect } from 'react'; const useInfiniteScroll = (isLastPage: boolean, fe

我试图开发一个定制的钩子,这似乎很容易,但我得到了一个错误

未捕获不变冲突:钩子调用无效。钩子只能在函数组件的主体内部调用。这可能是由于以下原因之一:

  • React和渲染器的版本可能不匹配(例如React DOM)
  • 你可能违反了钩子的规则
  • 同一应用程序中可能有多个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);
    

    EventsScene
    中,更改
    useInfiniteScroll
    以直接在函数体顶层调用(不确定为什么要首先创建此间接寻址):

    React只希望钩子调用为,因为它依赖于钩子的顺序始终相同。如果将钩子包装在函数中,则可能会在许多代码位置调用此函数,从而扰乱钩子的顺序

    每个组件都有一个内部“存储单元”列表。它们只是JavaScript对象,我们可以在其中放置一些数据。当调用像useState()这样的钩子时,它会读取当前单元格(或在第一次渲染时对其进行初始化),然后将指针移动到下一个单元格。这就是多个useState()调用每个获取独立本地状态的方式


    EventListPage
    是一个功能组件吗?您向它传递一个函数,该函数调用
    triggerFetchEvents
    prop.Hi,@DrewReese上的钩子。是的,它是一个功能组件。我添加了该组件的代码。查看我的更新。
    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;
    
    // before
    const useIn = () => useInfiniteScroll(isLastPage, fetchEvents);
    useIn();
    
    // after
    useInfiniteScroll(isLastPage, fetchEvents)