typescriptreact-stateremix.run

Store data from a form in a state before sending


I am creating a simple chat application using Remix. User shall enter a message and when clicking a submit button, the message is sent to the backend that creates a reply. Sending the message to the server works fine, but how can I locally save a copy of the message to display it in a chat history? Or in other words: how to access the form values on sending the form while still letting Remix do its job?

This is my code to send the chat message to the server:

// server side function
export async function action({
  request,
}: ActionFunctionArgs) {
  const formData = await request.formData();
  const chatMessage = formData.get("chatMessage");

  // generate chat reply on server side, no issue here
}

// client side code
<fetcher.Form method="post">
      <input
        type="text"
        name="chatMessage"
        placeholder="Enter your message"
      />
      <button type="submit">
        Send
      </button>
</fetcher.Form>

// TODO: keep a history of sent messages on the client

Solution

  • You can do it entirely client-side with a combination of useFetcher, useState, and useEffect, like this:

    import { useFetcher } from '@remix-run/react'
    import { useState, useEffect } from 'react'
    
    /* ... */
    
    export default function ChatRoute() {
      const fetcher = useFetcher()
      const [sentMessages, setSentMessages] = useState([])
    
      useEffect(() => {
        if (fetcher.state === 'submitting') {
          const chatMessage = fetcher.formData.get('chatMessage')
          setSentMessages([...sentMessages, chatMessage])
        }
      }, [fetcher.state])
    
      return (
        <>
          {/* ... */}
          <fetcher.Form method="post">
            <input
              type="text"
              name="chatMessage"
              placeholder="Enter your message"
            />
            <button type="submit">Send</button>
          </fetcher.Form>
          {/* ... */}
        </>
      )
    }