DEV Community

Cover image for Favorite Toggle Button with useOptimistic
Yuko
Yuko

Posted on

Favorite Toggle Button with useOptimistic

This is an idea of implementing a toggle button with useOptimistic. useOptimistic is a React experimental hook that allows apps to update UI optimistically while the actual state updates with async operation. You can learn more about it with those links.
useOptimistic - React
Data Fetching: Server Actions and Mutations | Next.js

Here is the main code of my component.

    import { useOptimistic, useRef } from 'react'
    import { Button } from './ui/button'
    import { HeartIcon, HeartFilledIcon } from '@radix-ui/react-icons'

    export function FavoriteButton({
      isFavorite,
      placeId,
    }: {
      isFavorite: boolean
      placeId: string
    }) {

      async function formAction(formData: FormData) {
        addOptimisticFavorite(!isFavorite)
        formRef.current?.reset()
        const placeId = formData.get('placeId')
        await fetch(`/api/favorite`, {
          method: 'POST',
          body: JSON.stringify({ placeId }),
        })
      }

      const [optimisticIsFavorite, addOptimisticFavorite] = useOptimistic(
        isFavorite,
        (state) => !state,
      )
      return (
        <form action={formAction} ref={formRef}>
          <input type="hidden" value={placeId} name="placeId" />
          <Button variant="ghost" type="submit" onClick={handleClick}>
            {optimisticIsFavorite ? <HeartFilledIcon /> : <HeartIcon />}
          </Button>
        </form>
      )
    }
Enter fullscreen mode Exit fullscreen mode

optimisticFavorite toggles immediately after users click the button and gets rolled back when the component receives isFavorite whose value is different from optimisticFavorite. Otherwise, optimisticFavorite keeps the client-side state.

In my real code, unfortunately, I needed to deal with two different cases to update isFavorite in my app, which is not ideal, and the code gets a little messy. Please visit the link below if you’re interested.
ai-gourmet-navigator/src/components/favorite-button.tsx at main ·…

That’s it! Thank you for reading :)

Top comments (0)