😸
nextjs上でPOSTしてページ遷移後にリロードするとSafariとChromeで挙動が違う
追記:2022/04/21
- issueのほうがクローズされました。要はブラウザのバグなので、Next.jsでは特に修正するつもりはない、というスタンスのようです。Safariの対応を首を長くして待つか、この方法を利用しないことをおすすめします。
※この問題自体はすでにissueに起票しています。
何が起きるか
タイトル通りではありますが、再現動画は以下のとおりです。
Google Chrome
Safari
何が起きているか
サンプルコードは以下に置いてますが、抜粋してコードを示すと次のようになります。
// pages/index.tsx
function Page() {
return (
<div>
<form action="/register" method="POST">
<button type="submit">Submit(POST)</button>
</form>
</div>
);
}
export default Page;
// pages/register.tsx
import React from "react";
import { GetServerSideProps, GetServerSidePropsContext, NextPage } from "next/types";
export type Props = {
requestMethod: string;
};
const Page: NextPage<Props> = (props) => {
return (
<div>
<h1>Request Method: {props.requestMethod}</h1>
</div>
);
};
export const getServerSideProps: GetServerSideProps = async ({ req }: GetServerSidePropsContext) => {
return {
props: {
requestMethod: req.method,
},
};
};
export default Page;
単純にフォームでPOSTしているだけですが、ChromeとSafariで挙動が違います。
なぜ発生するか
nextjs内部的にどうやらwindow.history.replaceState
を実行しているようで、これがブラウザの実装差異を踏み抜いているようです。
どっちが真なのかStackOverflowに投げてみています。
WebKit Bugzillaにはすでに先人がいて、2019年時点から発生しているようです。
whatwgの仕様を見る限りだと明確にどちらか正しいとは書いていないようにも(抽象的に書いているようにも)見えます。
まとめ
じゃあどうするか、という話ですが、nextjs側(ライブラリ側)で対応されればブラウザ間の挙動差異はなくなると考えられます。ブラウザの修正の方はIssueが立ってから3年経過しても動きはないので期待はできないでしょう。
ということで、現状はnextjsにおいてPOSTで遷移するのはSafariで挙動が違うのでやめて置くのが無難だろうという話でした。
Discussion