お知らせ

現在サイトのリニューアル作業中のため、全体的にページの表示が乱れています。

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>
  );
};