I have the following component:
const PostPage = () => {
const [post, setPost] = useState(null);
const [comments, setComments] = useState([]);
const router = useRouter()
useEffect(() => {
if (router.isReady) {
apiClient.get(`/posts/${router.query.id}/`)
.then((response) => {
setPost(response.data)
apiClient.get(`/comments/`).then((response) => {
setComments(response.data)
})})
.catch((error) => console.error('Error fetching post:', error));
};
}, [router.isReady]);
if (!post) {
return <p>Loading...</p>;
}
return (
<Grid container spacing={2}>
{PostDetails(post, comments)}
</Grid>
)
};
export default PostPage;
the Post Details component:
const PostDetails = (post={}, comments=[]) => {
const { title, author, content} = post;
const router = useRouter()
return (
<div>
{/* <Button variant="outlined" color="primary" onClick={() => router.back()}>Close Post</Button> */}
<Typography variant="h2">{title}</Typography>
<Typography variant="subtitle1">Author: {author}</Typography>
<Typography variant="body1" >{content}</Typography>
<Typography variant="h3">Comments:</Typography>
<List>
{comments.map((comment, index) => (
<Comment author={comment.author} text={comment.text} index={index}/>
))}
</List>
</div>
);
};
export default PostDetails;
When the Post component loads I get this error(If needed I can post the full error): Warning: React has detected a change in the order of Hooks called by PostPage.
It does render correctly but I still want to fix the error. It looks like it's pointing at the api call inside the useEffect hook, but I'm not sure what's wrong with it. An interesting thing I found is that if I remove the use of nextjs router in the PostDetails component the error does not appear, but I need it to have a navigation functionality.
I tried to read about the rules of hooks, checked I always initialize them unconditionally, and inside the component. I didn't find any info in the next router docs that are related to the issue.
You are calling your component as a regular function PostDetails(post, comments)
. Instead you need to call it as a JSX React Component, i.e. <PostDetails post={post} comments={comments} />
, otherwise React can't handle hooks correctly.
Just to give your more info, if we expand your code you are basically calling useRouter
after your "loading" if block:
if (!post) {
return <p>Loading...</p>;
}
return (
<Grid container spacing={2}>
{ // This call is basically inlined in runtime
// because it's just a regular function
PostDetails(post, comments)
// It expands in something like this:
const router = useRouter()
// And then you use your router here
// But this whole code comes after an `if` block
// which is against the rules of hooks
}
</Grid>
)