0

But I'm getting this strange behavior: every time I navigate to a site with a POST request through <Link />, I'll receive a 301 response.

I have to reload the page manually, and the form will submit adequately.

I'm currently using Remix.run 1.15.0 and now have the following config enabled:

/**
 * @type {import('@remix-run/dev').AppConfig}
 */
module.exports = {
  cacheDirectory: "./node_modules/.cache/remix",
  ignoredRouteFiles: ["**/.*", "**/*.css", "**/*.test.{js,jsx,ts,tsx}"],
  devServerPort: 8002,
  serverBuildTarget:
    process.env.NODE_ENV === "development" ? "node-cjs" : "vercel",
    server: process.env.NODE_ENV === "development" ? undefined : "./server.js",
    serverDependenciesToBundle: [/^validator*/, /^prisma/, /^@prisma\/client/],
    future: {
      v2_normalizeFormMethod: true,
      v2_meta: true,
      v2_errorBoundary: true,
  },
};

Here's the main Link component:

import type {
  CSSProperties,
  FunctionComponent,
  HTMLAttributeAnchorTarget,
} from "react";
import { Link as RemixLink } from "@remix-run/react";

export type LinkProps = {
  href?: string;
  /**
   * Local is Remix
   * Native is <a>
   */
  render?: "local" | "native";
  target?: HTMLAttributeAnchorTarget;
  searchParams?: URLSearchParams;
  className?: string;
  children: string | JSX.Element | (JSX.Element | undefined)[];
  style?: CSSProperties;
};

export const Link: FunctionComponent<LinkProps> = (props) => {
  const { href, render, children, className, searchParams } = props;

  if (render === "native") {
    <a
      href={href}
      style={props.style}
      target={props.target}
      rel={
        props.target === "_blank" ? "noopener noreferrer nofollow" : undefined
      }
      className={className}
    >
      {children}
    </a>;
  }

  return (
    <RemixLink
      target={props.target}
      rel={props.target === "_blank" ? "noopener nofollow" : undefined}
      to={{
        pathname: href,
        search: searchParams?.toString(),
      }}
      className={className}
      style={props.style}
    >
      {children}
    </RemixLink>
  );
};

I'm currently using it like:

<Link href={routes.admin.users.edit(u.id)} />

Additionally, I'm submitting my form using useSubmit, like this:

const submit = useSubmit();
const handleSubmit = (submitData) => {
    formData.append(defaults.submitKey, JSON.stringify(submitData));
    submit(formData, { method: "POST" });
}

And the action of the route is:


export async function action(args: ActionArgs) {
  const { request, context } = args;
  const { userId } = await getAdminUser(args);
  const formData = await request.formData();

  const formResult = validateFormData(formData, profileWithEmailSchema);
  console.log("Form Result", formResult);
  if (!formResult.success) {
    return validationError(formResult.errors);
  }

  const { dispatch } = context;

  const result = await dispatch({
    type: "UPSERT_USER_WITH_PROFILE_COMMAND_V2",
    arg: {
      ...formResult.data,
      socials: (formResult.data.socials || []) as Socials[],
      links: (formResult.data.links || []) as SocialLink[],
      uploadUserId: userId,
    },
  });

  console.log("Resssultt", result);

  if (result.isOk()) {
    return redirect(routes.admin.users.home);
  }

  const error = result.error;

  switch (error.type) {
    case "EmailAlreadyExists": {
      return jsonErrors({ email: t`Email already exists` });
    }
    case "InvalidEmail": {
      return jsonErrors({ email: t`Invalid email` });
    }

    case "HandlerExists": {
      return jsonErrors({ handler: t`Handler already exists` });
    }
    default: {
      return jsonErrors({ global: error.message });
    }
  }
}

Note: My submit form is rendered via an atomic-design architecture in which it lives outside the rendering function. I don't know if this could create problems.

https://github.com/remix-run/remix/issues/4183 How to use redirect from @remix-run/node

Jose A
  • 10,053
  • 11
  • 75
  • 108

0 Answers0