#Show error in client side while having serverside page

1 messages · Page 1 of 1 (latest)

upbeat stormBOT
#

Hi @little palm. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:

#

To show an error on the client side while having server-side code, you can utilize the built-in error handling mechanisms provided by Next.js. Specifically, you can use the Error component from next/error to render error messages on the client side.

Here's how you can modify your login function to handle errors and display them on the client side:

  1. Import the Error component from next/error.
  2. Catch errors in your login function and set the error state.
  3. Render the Error component conditionally based on the error state.

Here's an updated version of your LoginForm component:

import { useState } from "react";
import { Button, Form, Input, message } from "antd";
import { toUpperCase } from "../../utils";
import FormItem from "antd/lib/form/FormItem";
import InputPassword from "antd/lib/input/Password";
import { Icons } from "../Icons";
import { redirect } from "next/navigation";
import { cookies } from "next/headers";
import Link from "next/link";
import Error from 'next/error';

interface LoginFormValues {
  email: string;
  password: string;
}

const LoginForm = () => {
  const [error, setError] = useState(null);

  const login = async (values: LoginFormValues) => {
    "use server";
    try {
      const response = await fetch(
        `${process.env.NEXT_PUBLIC_API_URL}/auth/login`,
        {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
          },
          body: JSON.stringify(values),
        }
      );

      if (!response.ok) {
        throw new Error("ელ.ფოსტა ან პაროლი არასწორია!");
      }

      const data = await response.json();

      cookies().set("accessToken", JSON.stringify(data.accessToken));
      cookies().set("refreshToken", JSON.stringify(data.refreshToken));
      cookies().set("user", JSON.stringify(data.user));
#

redirect("/");
} catch (err) {
setError(err.message);
}
};

return (
<>
{error && <Error statusCode={500} title={error} />}
<Form onFinish={login} size="large">
<FormItem
name="email"
rules={[
{ required: true, message: "ელ.ფოსტა აუცილებელია!", type: "email" },
]}
>
<Input placeholder={toUpperCase("ელ.ფოსტა")} />
</FormItem>

    <FormItem
      name="password"
      rules={[{ required: true, message: "პაროლი აუცილებელია!" }]}
    >
      <InputPassword placeholder={toUpperCase("პაროლი")} autoComplete="on" />
    </FormItem>
 
    <Button type="primary" htmlType="submit" icon={<Icons.sendIcon />}>
      {toUpperCase("გაგზავნა")}
    </Button>
  </Form>
</>

);
};

export default LoginForm;


In this example:
- The `useState` hook is used to manage the error state.
- The `Error` component from `next/error` is used to display the error message on the client side.
- The `login` function catches any errors and sets the error state, which triggers the rendering of the `Error` component.

This approach ensures that errors are handled gracefully and displayed to the user without changing the code to client-side only.

For more information on error handling in Next.js, you can refer to the [Next.js Error Handling documentation](<https://nextjs.org/docs/pages/building-your-application/configuring>
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------
#

@little palm kapa.ai is still learning and improving, please let us know how it did by reacting below

little palm
#

If I have useState I have to write "use client" on top of the page, and I don't want that

#

@upbeat storm
If I have useState I have to write "use client" on top of the page, and I don't want that

upbeat stormBOT
#

Let me check the knowledge base for you. One moment! :books:

#

If you want to use useState but avoid adding "use client" at the top of your page, you can isolate the client-side logic into a separate component. This way, you can keep your main page as a server component and only mark the specific parts that need to be client-side.

Here's how you can achieve this:

  1. Create a separate client component for the form.
  2. Use the "use client" directive in that component.
  3. Import and use this client component in your main page.

Step 1: Create a Client Component

Create a new file, e.g., ClientLoginForm.tsx, and move the form logic there:

// ClientLoginForm.tsx
'use client';

import { useState } from 'react';
import { Button, Form, Input, message } from "antd";
import { toUpperCase } from "../../utils";
import FormItem from "antd/lib/form/FormItem";
import InputPassword from "antd/lib/input/Password";
import { Icons } from "../Icons";

interface LoginFormValues {
  email: string;
  password: string;
}

const ClientLoginForm = ({ login }) => {
  const [error, setError] = useState(null);

  const handleSubmit = async (values: LoginFormValues) => {
    try {
      await login(values);
    } catch (err) {
      setError(err.message);
    }
  };

  return (
    <>
      {error && <div className="error">{error}</div>}
      <Form onFinish={handleSubmit} size="large">
        <FormItem
          name="email"
          rules={[
            { required: true, message: "ელ.ფოსტა აუცილებელია!", type: "email" },
          ]}
        >
          <Input placeholder={toUpperCase("ელ.ფოსტა")} />
        </FormItem>
#

<FormItem
name="password"
rules={[{ required: true, message: "პაროლი აუცილებელია!" }]}
>
<InputPassword placeholder={toUpperCase("პაროლი")} autoComplete="on" />
</FormItem>

    <Button type="primary" htmlType="submit" icon={<Icons.sendIcon />}>
      {toUpperCase("გაგზავნა")}
    </Button>
  </Form>
</>

);
};

export default ClientLoginForm;


### Step 2: Use the Client Component in Your Main Page

Modify your main page to import and use the `ClientLoginForm` component:

```javascript
// main page file (e.g., page.tsx)
import { redirect } from "next/navigation";
import { cookies } from "next/headers";
import ClientLoginForm from './ClientLoginForm';

interface LoginFormValues {
  email: string;
  password: string;
}

const LoginForm = () => {
  const login = async (values: LoginFormValues) => {
    "use server";
    const response = await fetch(
      `${process.env.NEXT_PUBLIC_API_URL}/auth/login`,
      {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify(values),
      }
    );

    if (!response.ok) {
      throw new Error("ელ.ფოსტა ან პაროლი არასწორია!");
    }

    const data = await response.json();

    cookies().set("accessToken", JSON.stringify(data.accessToken));
    cookies().set("refreshToken", JSON.stringify(data.refreshToken));
    cookies().set("user", JSON.stringify(data.user));

    redirect("/");
  };

  return <ClientLoginForm login={login} />;
};

export default LoginForm;

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: