Skip to main content
React hooks for fetching and adding comments on goals, with support for authenticated users and guest comments.

useComments

Fetch all comments for a goal.
const { data, isLoading, error } = useComments(goalId)

Parameters

goalId
string
required
The ID of the goal to fetch comments for

Returns

data
Comment[]
Array of comments with user information, ordered by creation date (oldest first)
isLoading
boolean
Loading state of the query
error
Error | null
Error object if the query failed

Example

import { useComments } from '@features/goals/api/use-comments'

function CommentsList({ goalId }: { goalId: string }) {
  const { data: comments, isLoading } = useComments(goalId)
  
  if (isLoading) return <div>Loading comments...</div>
  
  return (
    <div>
      {comments?.map((comment) => (
        <div key={comment.id}>
          <strong>
            {comment.user?.email || comment.guest_label}
          </strong>
          <p>{comment.body}</p>
          <small>{new Date(comment.created_at).toLocaleString()}</small>
        </div>
      ))}
    </div>
  )
}

useAddComment

Add a new comment to a goal.
const { mutate, mutateAsync, isPending } = useAddComment()

Returns

mutate
(params: AddCommentParams) => void
Function to add a comment
mutateAsync
(params: AddCommentParams) => Promise<Comment>
Async function to add a comment and await the result
isPending
boolean
Loading state of the mutation

Parameters

goalId
string
required
The ID of the goal to add the comment to
body
string
required
The text content of the comment
guestLabel
string
The display name for guest users. Defaults to 'Guest'. Only used when the user is not authenticated.

Example

import { useAddComment } from '@features/goals/api/use-comments'
import { useState } from 'react'

function AddCommentForm({ goalId }: { goalId: string }) {
  const [body, setBody] = useState('')
  const { mutate: addComment, isPending } = useAddComment()
  
  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault()
    addComment(
      { goalId, body },
      {
        onSuccess: () => {
          setBody('')
        },
      }
    )
  }
  
  return (
    <form onSubmit={handleSubmit}>
      <textarea
        value={body}
        onChange={(e) => setBody(e.target.value)}
        placeholder="Add a comment..."
        required
      />
      <button disabled={isPending}>Post Comment</button>
    </form>
  )
}

Guest comments

When a user is not authenticated, comments are saved with a guest_label instead of a user ID:
import { useAddComment } from '@features/goals/api/use-comments'
import { useState } from 'react'

function GuestCommentForm({ goalId }: { goalId: string }) {
  const [body, setBody] = useState('')
  const [name, setName] = useState('')
  const { mutate: addComment, isPending } = useAddComment()
  
  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault()
    addComment({
      goalId,
      body,
      guestLabel: name || 'Anonymous',
    })
  }
  
  return (
    <form onSubmit={handleSubmit}>
      <input
        value={name}
        onChange={(e) => setName(e.target.value)}
        placeholder="Your name (optional)"
      />
      <textarea
        value={body}
        onChange={(e) => setBody(e.target.value)}
        placeholder="Add a comment..."
        required
      />
      <button disabled={isPending}>Post Comment</button>
    </form>
  )
}

Build docs developers (and LLMs) love