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
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)