[英]"React has detected a change in the order of Hooks" but Hooks seem to be invoked in order
我试图通过 React 的钩子使用Context
和Reducers
,但遇到了钩子顺序不固定的问题。 我的理解是,只要useHook(…)
的顺序保持不变,就可以在任何类型的控制流中调用返回的状态/更新函数/reducer。 否则,我将在 FunctionComponents 的最开始调用挂钩。
是我在循环中生成Days
吗? 还是缺少其他东西?
Warning: React has detected a change in the order of Hooks
called by Container. This will lead to bugs and errors if not fixed. For
more information, read the Rules of Hooks:
https://reactjs.org/docs/hooks-rules.html
Previous render Next render
------------------------------------------------------
1. useContext useContext
2. undefined useRef
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Container
的完整版本如下。 下面是Day
的摘录,并且有来自react-dnd
的useDrop
的引用。
export const Container: FunctionComponent<Props> = () => {
let events = useContext(State.StateContext)
//let events: Array<Event.Event> = [] <- with this, no warning
const getDaysEvents = (day: Event.Time, events: Array<Event.Event>) => {
return events.map(e => {
const isTodays = e.startTime.hasSame(day, "day")
return isTodays && Event.Event({ dayHeight, event: e })
})
}
let days = []
for (let i = 0; i < 7; i++) {
const day = DateTime.today().plus({ days: i })
days.push(
<Day key={day.toISO()} height={dayHeight} date={day}>
{getDaysEvents(day, events)}
</Day>
)
}
return <div className="Container">{days}</div>
}
Day
的摘录( Event
同样使用useDrag
钩子,也像这里一样在顶层调用)。
const Day: FunctionComponent<DayProps> = ({ date, height, children }) => {
const dispatch = useContext(State.DispatchContext)
const [{ isOver, offset }, dropRef] = useDrop({
// …uses the dispatch function within…
// …
})
// …
}
由于使用了短路逻辑,我在编写的组件中遇到了同样的错误消息。
这导致了一个错误:
const x = useSelector(state => state.foo);
if (!x) { return ; }
const y = useSelector(state => state.bar);
这是因为当x
为真时,钩子列表的长度为 2,但当x
为假时,列表的长度为 1。
为了解决这个错误,我不得不在任何提前终止之前使用所有钩子。
const x = useSelector(state => state.foo);
const y = useSelector(state => state.bar);
if (!x) { return ; }
写下我的评论作为答案:
问题是你直接调用Event.Event()
,即使它是一个反应组件。 这导致 react 将函数内部的钩子调用视为Container
一部分,即使您打算将它们作为 Event 的一部分。
解决方案是使用 JSX:
return isTodays && <Event.Event dayHeight={dayHeight} event={e} />
当您用生成的 JS 代码替换 JSX 时,为什么会更清楚:
return isTodays && React.createElement(Event.Event, { dayHeight, event: e })
请参阅https://reactjs.org/docs/react-api.html#createelement 。 你永远不想直接调用函数组件,react 的工作原理是你总是传递一个引用来响应组件,让它在正确的时间调用函数。
由于其他原因而不是这个问题,当您收到此error
它实际上是由于钩子实现的任何不良做法而发生的
不要在循环、条件或嵌套函数中调用 Hook。 相反,始终在 React 函数的顶层使用 Hooks
注意:首先在函数顶部实现你的
useState
钩子
不要从常规 JavaScript 函数调用 Hook
如果在测试组件时遇到此错误,请注意设置自定义钩子的位置(替换到函数顶部)
使用eslint对你的代码进行 lint 避免出现React Hooks Rules错误
使用 npm 或 yarn 安装包
npm install eslint-plugin-react-hooks --save-dev
这不是问题场景,而是错误本身,希望它会帮助某人:)
const { chatSession, userBelongsToSession } = useChatSession(session_id)
const { activeSession, setActiveSession } = useActiveChatSession()
const isCurrentActiveSession = useMemo(() => activeSession != null && activeSession.session_id === session_id, [activeSession, session_id])
if (chatSession == null || activeSession == null) {
return (<div></div>)
}
const Container = styled(BorderedContainer)`height: 72px; cursor: pointer;`
我在这段代码中发生了同样的错误,并且与样式组件调用 useRef 相关,并且之前由于条件渲染而未调用
if (chatSession == null || activeSession == null) {
return (<div></div>)
}
默认情况下,钩子将返回 null 并且我的组件将在不使用 useRef 的情况下呈现,尽管当钩子实际填充时,样式组件将生成一个带有 useRef 的组件。
if (chatSession == null || activeSession == null) {
return (<div></div>)
}
const Container = styled(BorderedContainer)`height: 72px; cursor: pointer;
我在 react-native 应用程序中也遇到了同样的问题。 这是由于不必要的元素加载过程而发生的。
旧代码
return (......
<NotificationDialog
show={notificationPayload !== null}
title={notificationPayload?.title}
.......
/>
);
这将重新渲染 NotificationDialog 甚至 notificationPayload !== null。 但它不是必需的。 简单地我添加了这个空检查并避免呈现这个 NotificationDialog 如果它为空
使固定
return (......
{ notificationPayload !== null? <NotificationDialog
show={notificationPayload !== null}
title={notificationPayload?.title}
.......
/> : null }
);
在我编写的测试中调用不同的钩子方法时,我随机收到此错误。 对我的修复是在我实施的useRef
间谍中:
const useRefSpy = jest
.spyOn(React, 'useRef')
.mockReturnValueOnce({ whatever })
将mockReturnValueOnce
更改为mockReturnValue
修复了错误。
就我而言,我正在执行多个 api 调用并将它们中的每一个保存到不同的状态,这导致我出现此错误。 但是在将其更改为单个状态后,我能够克服它。
const [resp, setGitData] = useState({ data: null, repos: null });
useEffect(() => {
const fetchData = async () => {
const respGlobal = await axios(
`https://api.github.com/users/${username}`
);
const respRepos = await axios(
`https://api.github.com/users/${username}/repos`
);
setGitData({ data: respGlobal.data, repos: respGlobal.data });
};
fetchData();
}, []);
我通过将导入的组件用作组件而不是 function 解决了我的问题,我不得不返回 jsx ( <>{values}</>
) 而不仅仅是值,因为我必须在 ConvertDate 中导入 redux 的 useSelector,显然它没有如果它只是一个 function,则不能使用 useSelector。我可以只使用 function 并将日期和 redux 的 state 作为道具传递...
我有什么:
<b>{ConvertDate({ date: post.dateTime })}</b>
以及我如何修复它:
<b>{<ConvertDate date={post.dateTime} />}</b>
我知道我来晚了,但只是想分享我在同一个错误堆栈上的经验。
在ReactJS
17 中,tanstack 的useQuery
4 和useEffect
的组合发生在我身上。
这里有一场精彩的讨论。
堆栈跟踪:
react_devtools_backend.js:4026 Warning: React has detected a change in the order of Hooks called by Applicants. This will lead to bugs and errors if not fixed. For more information, read the Rules of Hooks: https://reactjs.org/link/rules-of-hooks
Previous render Next render
------------------------------------------------------
1. useContext useContext
2. useContext useContext
3. useState useState
4. useRef useRef
5. useEffect useEffect
6. useRef useRef
7. useEffect useEffect
8. useContext useContext
9. useState useState
10. useRef useRef
11. useEffect useEffect
12. useRef useRef
13. useEffect useEffect
14. useState useState
15. useState useState
16. useState useState
17. useState useState
18. useState useState
19. useState useState
20. useContext useContext
21. useContext useContext
22. useContext useContext
23. useContext useContext
24. useEffect useEffect
25. useState useState
26. useCallback useCallback
27. useState useState
28. useLayoutEffect useLayoutEffect
29. useEffect useEffect
30. useDebugValue useDebugValue
31. useEffect useEffect
32. undefined useEffect
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
所以它正在发生,因为我在useQuery
api 回调行之后使用了useEffect
,我通过将useEffect
放在useQuery
行之前解决了这个问题,并且所有警告堆栈跟踪都得到了解决。
希望它能帮助别人。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.