skip to Main Content

in NextJs I want to create a component that displays a form, and fill this form by values from database.

the problem is that client component doesn’t support aync/await and server components doesn’t support neither useFormState() nor event handlers

async function MyForm({id}){

// supported in Client components only
let [state, submitAtion] = useActionState(...);

  // await is supported in server components only
   let value = await fetch(`https://example.com/value/${id}`);

// event handler is supported in Client components only
clickHandler(ev){
 // handle the form
}

return (
 <>
  <form action={submitAtion}>
  <input value={content} onChange={...} />
  <button type="submit" />Submit</button>
  <button onClick={clickHandler}>Submit</button>
  </form>
 </>
)
}

trials:

1- using server actions, but useActionState() and useFormState() are supported in client components only

2- convert MyForm into a client component, but async/await is not supported in client components

3- move the button to a separate client component and keep the form in a server component, but the button cannot access the form data, and we cannot pass a function from MyForm into MyButton as it is not a serializable value

2

Answers


  1. the problem is that client component doesn’t support aync/await

    It doesn’t need to. You can use state to update the value being fetched from the server, and fetch that value in a useEffect. For example:

    function MyForm({id}){
    
      let [state, submitAtion] = useActionState(...);
      // track the asynchronous value in state
      let [value, setValue] = useState();
      
      // invoke the asynchronous operation whenever "id" changes
      useEffect(() => {
        (async () => {
          // update state with the new value
          const response = await fetch(`https://example.com/value/${id}`);
          const result = await response.text(); // or json?
          setValue(result);
        })();
      }, [id]);
    
      clickHandler(ev){
        // handle the form
      }
    
      return (
        <>
          <form action={submitAtion}>
            <input value={content} onChange={...} />
            <button type="submit" />Submit</button>
            <button onClick={clickHandler}>Submit</button>
          </form>
        </>
      );
    }
    

    When the component initially renders, value will be undefined (or will be whatever initial value you provide to useState() if you like). After the fetch operation completes, the state value will be updated and the component will re-render.

    Login or Signup to reply.
  2. You do not need form states to submit a form to a server action.

    Simply write your form in a server component and create a function for handling the data in your page file. Make sure to include "use server"; in the top like this:

    async function handleSubmit(formData) {
        "use server";
    
        console.log(formdata.get('myinput'))
        // Add logic here
    }
    

    And then in your Form Component you add the name attribute to your input fields which will later be their identifier in the formData object.

    Like this:

    <>
        <form action={handleSubmit}>
            <input name="myinput" defaultValue={...} />
            <button type="submit">Submit</button>
        </form>
    </>
    

    You do not need to pass a value or onChange property to the input fields. Just the defaultValue, which you fetched on the server-side.
    Make sure that your button is of type submit, so that it triggers the form action.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search