我试图通过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…
// …
})
// …
}
9条答案
按热度按时间oaxa6hgo1#
由于使用了短路逻辑,我在编写组件时遇到了同样的错误消息。
这会导致错误:
这是因为当
x
为真时,钩子列表的长度为2,但是当x
为假时,列表的长度为1。为了解决这个错误,我不得不把所有的钩子使用之前,任何提前终止。
dgenwo3n2#
写我的评论作为回答:
问题是你直接调用了
Event.Event()
,尽管它是一个react组件,这会导致react将函数内部的钩子调用视为Container
的一部分,尽管你本打算将它们作为Event的一部分。解决方案是使用JSX:
return isTodays && <Event.Event dayHeight={dayHeight} event={e} />
当您将JSX替换为生成的JS代码时,就可以更清楚地了解为什么会这样了:
return isTodays && React.createElement(Event.Event, { dayHeight, event: e })
请参见https://reactjs.org/docs/react-api.html#createelement。您永远不想直接调用函数组件,react的工作原理是,您总是将一个引用传递给要做出React的组件,让它在正确的时间调用函数。
tpgth1q73#
因为其他原因而不是这个问题,当你收到这个
error
它实际上是由于任何不好的钩子实现实践而发生的
1 -仅顶级的呼叫挂接
不要在循环、条件或嵌套函数内调用挂钩。相反,应始终在React函数的顶层使用挂钩
注意:首先在函数顶部实现
useState
挂钩2 -仅从React函数调用挂接
不要从常规JavaScript函数调用挂钩
3 -测试期间出现错误
如果在测试组件时出现此错误,请注意设置自定义挂钩的位置(替换到函数的顶部)
最佳实践
对lint使用eslint,您的代码将避免出现React Hooks规则错误
安装带有npm或Yarn的卷装
7uzetpgm4#
从useEffect调用多个API调用
在我的例子中,我做了多个api调用,并将每个调用保存到不同的状态,这导致了这个错误。但是在将其更改为一个状态后,我能够克服这个错误。
rjee0c155#
这不是问题场景,但这是错误本身,希望它能帮助一些人:)
在这段代码中,我也遇到了同样的错误,这与样式化组件调用useRef有关,而之前由于条件渲染而没有调用useRef
默认情况下,钩子将返回null,我的组件将不使用useRef呈现,尽管当钩子实际被填充时,样式化组件将生成一个使用useRef的组件。
fafcakar6#
在我编写的测试中,当我调用不同的钩子方法时,我随机地得到了这个错误。我的修复方法是在我实现的
useRef
的spy中:将
mockReturnValueOnce
更改为mockReturnValue
修复了错误。g6baxovj7#
我在react-native应用程序中也遇到了同样的问题。这是由于不必要的元素加载过程造成的。
旧代码
这将重新呈现NotificationDialog,即使notificationPayload!== null。但这不是必需的。我只是添加了此null检查,并避免在此NotificationDialog为null时呈现它
固定了
fae0ux8s8#
我通过将导入的组件作为组件而不是函数来修复我的问题,我必须返回jsx(
<>{values}</>
)而不仅仅是值,因为我必须在ConvertDate中导入redux的useSelector,显然如果它只是一个函数,它就不能与useSelector一起工作。我可以只使用一个函数,并将日期和redux的状态作为属性来传递...我拥有的:
还有我是怎么解决的:
cl25kdpy9#
我知道我迟到了,但我只是想分享我的经验,在同一个错误堆栈。
对于我来说,这种情况发生在tanstack的
useQuery
4和ReactJS
17中的useEffect
的组合上。一个美丽的讨论here。
堆栈跟踪:
因此,它发生了,因为我在
useQuery
API回调行之后使用了useEffect
,我通过将useEffect
放在useQuery
行之前解决了这个问题,所有警告堆栈跟踪都得到了解决。希望能帮到什么人。