Reactでのページ間データ保持について

React で SPA を組んでいてブラウザバックしたときのフォームの入力内容が消し飛んで気になったので、ブラウザバックした時にどうなるのかというのを軽く調査した結果

確認したパターンとしては次の 2 つ

  1. フォームの入力値を DOM に保持させるステートレスな方式
  2. フォームの入力値を JS に保持させるステートフルな方式

LocalStorage に画面情報を保存して復元するとか、条件分岐を使って DOM を隠して保持させるとか、そういう系は考慮しない

結果

DOM 保持 JS 保持
SPA 内ブラウザバック 消える 保持される
SPA 外ブラウザバック 保持される 消える
コード記述量 少ない 多い

1. フォームの入力値を DOM に保持させるステートレスな方式

この方式だと history.push() で DOM が消し飛ぶので SPA 内でのブラウザバックで入力したデータが保持されません
その代わり SPA の外、別のサイトに遷移してからブラウザバックしたときは、DOM が残っているので入力したデータが保持されます

2. フォームの入力値を JS に保持させるステートフルな方式

この方式だと JS でステート管理をしているため、history.push() で遷移して DOM が消し飛んでも、 defaultValue に持ってる値を突っ込んであげれば、取り敢えず入力したデータを保持することが出来ます
反対に SPA の外、別のサイトに遷移してからブラウザバックしたときは、メモリの中身が飛んでるので入力したデータが保持されません

各手法の実装方式

ちゃちゃっと書いたのでコードは超雑です

確認環境

Env Ver
react 17.0.2
react-dom 17.0.2
react-router-dom 5.2.0

1. フォームの入力値を DOM に保持させるステートレスな方式

大正義ステートレスです
Function Component はステートレスなので、こうあってほしいですよね~
コードもシンプルで管理しやすいのが素敵なところです

export const StatelessPage = () => {
  const history = useHistory();
  return (
    <div>
      <form>
        <input type="text" />
        <button onClick={() => history.push(AppRoute.dom2.path)}>submit</button>
      </form>
    </div>
  );
};

2. フォームの入力値を JS に保持させるステートフルな方式

ギルティなステートフル方式です
Class Component を捨てたはずなのにどうしてこうなった…
コードが煩雑で管理が大変です

export const StatefullPage = () => {
  const ctx = useContext(ExampleContext);
  const history = useHistory();
  const onChange = (ev: React.ChangeEvent<HTMLInputElement>) => {
    ctx.text = ev.target.value;
  };

  return (
    <div>
      <form>
        <input
          type="text"
          defaultValue={ctx.text}
          onChange={(ev) => onChange(ev)}
        />
        <button onClick={() => history.push(AppRoute.ctx2.path)}>submit</button>
      </form>
    </div>
  );
};