kirill ras
kirill ras

Reputation: 45

Change in the order of hooks when calling API inside useEffect

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.

Previous render Next render

  1. useState useState
  2. useState useState
  3. useContext useContext
  4. useEffect useEffect
  5. undefined useContext ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ at PostPage (webpack-internal:///./pages/posts/[id].jsx:20:76)

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.

Upvotes: 0

Views: 81

Answers (1)

Danila
Danila

Reputation: 18536

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

Upvotes: 1

Related Questions