nehalist
nehalist

Reputation: 1496

Update server-side rendered props dynamically

I've got posts with comments and like to implement a post view that includes all comments to that post.

My getServerSideProps passes the post (including all comments) to my page. Whenever a new comment is written the comments should be dynamically updated, but I'm currently facing some problems with that.

My post view:

const PostView: NextPage = ({ post }) => {
  return (
    <Layout>
      {post.title}
      <CommentList initialComments={post.comments} postId={post.id} />
    </Layout>
  );
};

export default PostView;

export const getServerSideProps = () => {
  const post = await getPost(); // returns the post and all its comments
  return { props: { post } };
};

The CommentList component:

const CommentList = (initialComments, postId) => {
  const { data: comments } = useQuery(["comments", postId], async () => getComments(), { initialData: initialComments);

  return (
    <>
      Comments: {comments.length}
      ... new comment form ...
      ... list of comments ...
    </>
  );
}

The reason why I still want to query comments with react-query is simple: comments should be server-side rendered so that they become seo-relevant, while I want human users to get a dynamic list that can be updated.

When writing new comments I update the QueryClient of react-query by hand:

export const useCreateCommentMutation = (postId: string) => {
  const queryClient = useQueryClient();

  return useMutation(
    ["comments", postId],
    async (values) =>
      await axios.post("/api/comments", values),
    {
      onSuccess: async res => {
        queryClient.setQueryData<CommentWithAuthor[]>(
          ["comments", postId],
          prev => [...(prev || []), res.data],
        );
      },
    },
  );
};

This seems to work at first glance; when I check the DOM the comments are included and when writing new comments they dynamically appear.

Unfortunately, when I refresh the page I get the following error:

Text content did not match. Server: "3" Client: "4"

3 (or 4) in this case is the comments.length output.

What am I doing wrong in this case?

Thanks

Edit 1:

I've also tried fixing it by using useEffect:

const [usedComments, setUsedComments] = useState([]);

  useEffect(() => {
    setUsedComments(comments || initialComments);
  }, [comments])

And render usedComments instead - but unfortunately now the comments are no longer part of the DOM.

Upvotes: 3

Views: 596

Answers (1)

c9der
c9der

Reputation: 114

Why don't you try using useState() hook to store that the Comment data . Every time useQuery runs it will update the state which will cause re-rendering of the comment and also. I can't think of anything other then this. I don't know what your comment json/data look like to do the server side dynamic rendering.

And useQuery runs on user action like click on add new comment button or a time loop.

and your error seems like It is caused by some Server and client attribute of component.

Upvotes: 0

Related Questions