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