はじめに
業務で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
を利用して値を保持する方法の解説と具体例の列挙をしました。フロントエンドのデバックは苦労したので、これからも調べた知見をまとめていこうと思います。
ありがとうございました。