Reputation: 16372
I am trying to use Context
and Reducers
via React's hooks, and running into problems with the order of the hooks not being constant. My understanding was that as long as the order of the useHook(…)
remained the same, it was fine to invoke the returned state/update function/reducer in any sort of control flow. Otherwise, I'm invoking the hooks at the very beginning of the FunctionComponents.
Is it that I'm generating Days
in a loop? Or missing something else?
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
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The full version of Container
is below. An excerpt from Day
is below, and has a ref from react-dnd
's 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>
}
An excerpt from Day
(Event
similarly uses a useDrag
hook, also called at the top level just like here).
const Day: FunctionComponent<DayProps> = ({ date, height, children }) => {
const dispatch = useContext(State.DispatchContext)
const [{ isOver, offset }, dropRef] = useDrop({
// …uses the dispatch function within…
// …
})
// …
}
Upvotes: 142
Views: 156542
Reputation: 11
This might be late but maybe someone has a issue similar to the one i had, also i see no one mentioned this point as well.
React has detected a change in the order of Hooks called by AppConnectionWizard. This will lead to bugs and errors if not fixed. For more information, read the Rules of Hooks: https://react.dev/link/rules-of-hooks
Previous render Next render
------------------------------------------------------
1. useContext useContext
2. useContext useContext
3. useContext useContext
4. useContext useContext
5. useContext useContext
6. useContext useContext
7. useContext useContext
8. useState useState
9. useState useState
10. useState useState
11. useState useState
12. useState useState
13. useState useState
14. useState useState
15. useState useState
16. useState useState
17. useContext useContext
18. useMemo useMemo
19. useContext useContext
20. useMemo useMemo
21. useState useState
22. useState useState
23. useContext useContext
24. useContext useContext
25. useContext useContext
26. useState useState
27. useContext useContext
28. useEffect useEffect
29. useState useState
30. useState useState
31. useContext useContext
32. useMemo useMemo
33. useEffect useEffect
34. useEffect useEffect
35. useEffect useEffect
36. useEffect useEffect
37. useContext useEffect
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Error Component Stack
I resolved it, by ordering my hooks differently, and grouping all similar hooks together.
Have your useState
hooks together, then after that, have your useEffect
hooks, do not mix up the hooks, in the component's body.
if you have a custom hooks, also order the hooks same way, and place it before the useEffect
hooks in the main component body.
Upvotes: 1
Reputation: 67
I was getting following error : Warning: React has detected a change in the order of Hooks called by Body. 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 ------------------------------------------------------
The issue was, while adding custom hook to parent component the sequence got disturbed and hence was throwing error
Upvotes: 0
Reputation: 20080
In my case i bring inline useCallback event to outside not its working fine.
Previous render Next render
------------------------------------------------------
1. useState useState
2. useState useState
3. useEffect useEffect
4. useEffect useEffect
5. useCallback useCallback
6. undefined useCallback
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Error:
<EnhancedTable
onRowClick={useCallback((event, data) => setSelectedRow(data), [])}
options={isEmpty(selectedRow) ? {
exportButton: false,
filtering: false,
paging: false,
search: true,
} : {
exportButton: false,
filtering: false,
paging: false,
rowStyle: (data, rowData) => data.tableData.id === selectedRow?.tableData?.id && { background: '#1e88e5', color: 'white' },
search: true,
}}
columns={[
{ field: 'applicationUse.application.applicationDisplayName', title: 'Application' },
{ field: 'applicationUse.code', title: 'Application Use' },
{ field: 'shortName', title: 'Short Name' },
{ field: 'entityStatus.code', title: 'Status'},
]}
data={lookUpClients}
title={''}
/>
Solution:
const onRowClickEvent = useCallback((event, data) => setSelectedRow(data), [])
<EnhancedTable
onRowClick={onRowClickEvent} // here we given function instead of inline function
options={isEmpty(selectedRow) ? {
exportButton: false,
filtering: false,
paging: false,
search: true,
} : {
exportButton: false,
filtering: false,
paging: false,
rowStyle: (data, rowData) => data.tableData.id === selectedRow?.tableData?.id && { background: '#1e88e5', color: 'white' },
search: true,
}}
columns={[
{ field: 'applicationUse.application.applicationDisplayName', title: 'Application' },
{ field: 'applicationUse.code', title: 'Application Use' },
{ field: 'shortName', title: 'Short Name' },
{ field: 'entityStatus.code', title: 'Status'},
]}
data={lookUpClients}
title={''}
/>
Upvotes: 1
Reputation: 3308
use eslint-plugin-react-hooks
as it will help you easily identify the rootcause in your component code.
React documentation here: https://reactjs.org/docs/hooks-rules.html#eslint-plugin
Upvotes: 0
Reputation: 4935
I know I'm very late, but just wanted to share my experience on the same error stack.
It happened for me for the combination of tanstack's useQuery
4 and useEffect
in ReactJS
17.
One beautiful discussion here.
Stacktrace:
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
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
So it were happening, due to I were using the useEffect
after the useQuery
api callback line, which I resolved by putting the useEffect
before the useQuery
line, and all warning stack trace got solved.
Hope it would help someone.
Upvotes: 4
Reputation: 709
i fixed my issue by using an imported component as a component and not as a function, i had to return jsx (<>{values}</>
) instead of just values because i had to import redux's useSelector inside ConvertDate, apparently it doesn't work with useSelector if it's just a function. I could've just use a function and pass the date and the redux's state as props though...
what i had:
<b>{ConvertDate({ date: post.dateTime })}</b>
and how i fixed it:
<b>{<ConvertDate date={post.dateTime} />}</b>
Upvotes: 0
Reputation: 1934
in my case i was doing multiple api calls and saving each of them to different state, which led me to this error. But after changing it into a single state i was able to overcome that.
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();
}, []);
Upvotes: 4
Reputation: 329
I was getting this error randomly while calling different hook methods in the test I was writing.
The fix for me was in the spy of useRef
I had implemented:
const useRefSpy = jest
.spyOn(React, 'useRef')
.mockReturnValueOnce({ whatever })
Changing the mockReturnValueOnce
to mockReturnValue
fixed the error.
Upvotes: 3
Reputation: 2165
For other reason instead of this question, when you receive this error
It actually happens because of any bad practice for hook implementations
Don’t call Hooks inside loops, conditions, or nested functions. Instead, always use Hooks at the top level of your React function
NOTE: Implement your
useState
hooks first at top of the function
Don’t call Hooks from regular JavaScript functions
If you get This Error when testing the component, be careful to where you set your custom hooks (replace to top of the function)
use eslint for lint your code avoid geting React Hooks Rules errors
install package with npm or yarn
npm install eslint-plugin-react-hooks --save-dev
Upvotes: 27
Reputation: 2525
I got the same issue in the react-native application as well. It has happened due to the unnecessary elements loading process.
old code
return (......
<NotificationDialog
show={notificationPayload !== null}
title={notificationPayload?.title}
.......
/>
);
This will re-render NotificationDialog even notificationPayload !== null. But it is not needed. Simply I added this null check and avoid render this NotificationDialog if it is null
fix
return (......
{ notificationPayload !== null? <NotificationDialog
show={notificationPayload !== null}
title={notificationPayload?.title}
.......
/> : null }
);
Upvotes: 0
Reputation: 526
It is not the question scenario, but it is the error itself, hopefully, it will help somebody :)
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;`
The same error happens to me in this piece of code and is related to useRef being called by styled-components and not being called before because of conditional rendering
if (chatSession == null || activeSession == null) {
return (<div></div>)
}
by default, the hooks will return null and my component will render with no useRef, although when the hooks are actually populated, styled-components will then generate a component with useRef.
if (chatSession == null || activeSession == null) {
return (<div></div>)
}
const Container = styled(BorderedContainer)`height: 72px; cursor: pointer;
Upvotes: 2
Reputation: 7113
Writing my comment as an answer:
The problem is that you're calling Event.Event()
directly, even though it is a react component. That causes react to treat the hook calls inside the function as part of Container
, even though you meant for them to be part of Event.
The solution is to use JSX:
return isTodays && <Event.Event dayHeight={dayHeight} event={e} />
Why this works is clearer when you replace the JSX with the resulting JS code:
return isTodays && React.createElement(Event.Event, { dayHeight, event: e })
See https://reactjs.org/docs/react-api.html#createelement. You never want to call the function components directly, how react works is that you always hand a reference the component to react and let it call the function at the correct time.
Upvotes: 61
Reputation: 8645
I ran into this same error message in a component I was writing due to use of short-circuiting logic.
This resulted in an error:
const x = useSelector(state => state.foo);
if (!x) { return ; }
const y = useSelector(state => state.bar);
This is because when x
is truthy the list of hooks has length 2, but when x
is falsey the list has length 1.
To resolve the error I had to put all hook use before any early terminations.
const x = useSelector(state => state.foo);
const y = useSelector(state => state.bar);
if (!x) { return ; }
Upvotes: 122