5
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Reactでブラウザバック時のフォームデータ保持方法

Posted at

はじめに

業務でReactアプリケーションのデバッグを行う中で、ブラウザバック時にフォームの値がリセットされる問題に直面しました。この問題の解決方法を共有します。

値を保持の方法とは

historyオブジェクトやlocalStorageを使う方法も考えられますが、今回はセッションごとにデータを管理できるsessionStorageを使うことにしました。

sessionStorageを使って値を保持する

コードを書いていると気づいたのは、useEffectを利用して保存や復元をするのがやりやすいということです。この章では、いくつかの具体例を列挙していくので参考になりそうなコードがあれば流用してください。

初期値なしの保存・復元

const [value, setValue] = useState<string>()

// 何かしらの処理実行
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
  const inputValue = e.target.value
  setValue(inputValue)
  sessionStorage.setItem('formValue', inputValue)
}

// valueの保存
useEffect(() => {
  if (value) {sessionStorage.setItem('value', value)}
}, [value])

// valueの復元
useEffect(() => {
	const savedValue = sessionStorage.getItem('value')
  if (savedValue) {setLabel(savedValue)}
}, [])

初期値がない状態で保存と復元を効率よく行いたい場合に、便利に利用できます。今回デバッグしていて、もっとも利用しました。

初期値ありの保存・復元

const initLabel = '値を入力してください'
const [label, setLabel] = useState<string>(initLabel)

// labelの保存
useEffect(() => {
  // labelがinitLabelの場合は保存しない
  if (label && label !== initLabel) {
  sessionStorage.setItem('labelText', label)
  }
}, [label, initLabel])

// labelの復元
  useEffect(() => {
    const savedLabelText = sessionStorage.getItem('labelText')

    // 保存されている値がある場合は復元
    if (savedLabelText) {
      setLabel(savedLabelText)
    }
  }, [])

上記では、labelに初期値が入っている場合は保存しません。そしてuseEffectを利用して、labelの値が変化するたびに保存用のuseEffectも実行されます。(正しくはlabelの復元も実行されますが…)

文字配列の保存・復元

const [label, setLabel] = useState<string[]>()

...
// 何かしらの処理でsetLabel(○○)を利用
...

// labelの保存
useEffect(() => {
  if (label) {
  sessionStorage.setItem('labelText', JSON.stringify(label))
  }
}, [label])

// labelの復元
  useEffect(() => {
    const savedLabelText = sessionStorage.getItem('labelText')

    // 保存されている値がある場合は復元
    if (savedLabelText) {
      setLabel(JSON.parse(savedLabelText))
    }
  }, [])

こちらもデバッグしていて、よく記述したコードです。

辞書型の各データの保存と復元

const {
    getValues,
    watch,
    reset,
    register,
    setValue
  } = useForm<VoucherSearchFormData>({
    defaultValues: {
      keyword: '',
      categories: []
    }
  })
  // categoriesの保存
  useEffect(() => {
    const subscription = watch((value) => {
      const { categories } = value
      if (categories && categories.length > 0) {
        sessionStorage.setItem('selectedCategories', JSON.stringify(categories))
      }
    })

    return () => subscription.unsubscribe() // クリーンアップ
  }, [watch])
  
  // categoriesの復元
  useEffect(() => {
    const selectedCategories = sessionStorage.getItem('selectedCategories')
    if (selectedCategories) {
      const categories: string[] = JSON.parse(selectedCategories)
      setValue('categories', categories)
    }
  }, [setValue])

  // keywordの保存
  useEffect(() => {
    const subscription = watch((value) => {
      const { keyword } = value
      if (keyword !== undefined && keyword !== '') {
        sessionStorage.setItem('keyword', keyword)
      }
    })

    return () => subscription.unsubscribe() // クリーンアップ
  }, [watch])

  // keywordの復元
  useEffect(() => {
    const savedKeyword = sessionStorage.getItem('keyword')
    if (savedKeyword) {
      setValue('keyword', savedKeyword)
    }
  }, [setValue])

最初はgetValuesを利用して値の保存をしていたのですが、うまく保存ができなかったので、useFromの機能の一つであるwatchを利用することで、辞書型のデータが変化するたびにうまく保存してくれるようになりました。

最後に

今回はsessionStorage を利用して値を保持する方法の解説と具体例の列挙をしました。フロントエンドのデバックは苦労したので、これからも調べた知見をまとめていこうと思います。

ありがとうございました。

参考記事

ブラウザバック時にReactでもフォームの値を保持したい! - Qiita

5
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?