こんにちは。てぃろです。
今回はReactのTipsです。
Reactは親子関係にあるコンポーネント同士での値の受け渡しにはProps
を使うなどわかりやすい方法がしっかり用意されています。
ただ、今回は親子関係にないコンポーネント同士での値の受け渡しをどのようにやればシンプルなのか?を考えました。
URLを使ってもいい
親子関係にないコンポーネント同士での値の受け渡し には、いくつか方法があると思ってます。
- Reduxを使う
- 値を共通的に参照可能なコンポーネントを別に作る
- LocalStorageやSessionStorageを使う
- URLを使う
- ハッシュを使う
- 外部のDBに持たせる
他にも方法があるかもしれませんが、今私が思いついたのはこれくらいです。
今回に関しては、渡したいパラメータは1つだけだったので追加のライブラリを使ったり外部の記憶領域を使って複雑性が上がるような実装にはしたくありません。
値を1つ渡したいためだけに、参照用のコンポーネントを作るのもつらい…。
そこで、一番簡単でシンプルなURLを使うことにしました。
ハッシュも簡単なのですが、URLが変わったタイミングで処理を走らせたかったので、今回はその使い方ができなくて見送りました。
他にも、そのパラメータがアプリの全体的な挙動に影響するような値でありURLに含まれていても自然であったということも理由としては大きいです。逆にURLパラメータとして不自然であったなら、このような選択はせず参照用のコンポーネントを新たに作るとかしていたかもしれないです。
例えば以下のような場合にはURLパラメータを使うべきではないのではないでしょうか。
- そのパラメータが秘匿すべき情報である(クレジットカード番号、など)
- パラメータを悪用すると、クラックされる危険性がある(他人の個人情報が見える、など)
- URLをシェアされたときに見た目が悪い(長すぎる、可読性がない)
URLで親子関係にない値渡しの実装
では、今回実際にどんな実装をしたのかご紹介します。
使用したライブラリは、React Router v5です。最新はv6ですが、今回はv5で考えました。
React RouterはReactでページ遷移を簡単にできるライブラリですが、以下に紹介する実装はv6ではなくなってしまったらしく、これがやりたいならv5を使わなければいけません。
では実装ですが、まず受け取る側での実装です。
const history = useHistory<CustomState>();
const location = useLocation<CustomState>();
useEffect(() => {
history.listen((location) => {
console.log(location.pathname) // URLを出力
someFunc(location.state.someValue); // URLが変わったときに実行する処理
})
}
この実装をすることで、URLが変わるたびにlocation
からURLを得ることができます。
更にいえば、このlocation
はstate
というパラメータを持っており、そこでURL以外の値も渡すことができます。
上記はstate
にセットしたsomeValue
の値を取得して処理を実行する例です。
これだけみると、stateでなんでも渡せてしまうので、URLを使わなくてもいい気がしてきました・・・。うーん。。。
ちなみに、値を渡すときには通常通り以下のように実装します。
const history = useHistory<CustomState>();
history.push({
pathname: `/path/to/next`,
state: {someValue: "hoge"},
});
最後にポイントですが、上記のようにuseHistory
に対してCustomState
という形でstate
の型を指定しておくことです。
これをしておかないと、location.state.someValue
として値を取得する際に、location.state
の型がunknownになってしまい、値をうまく取得できません。
結果的に、使わなかったURLでの値渡し
いろいろ実装を検証した結果、これを使わない実装のほうが画面上もきれいになっていくかと思い直しました。
こうして検証することで、実装もより美しく機能的になっていけるということで必要なプロセスだったと思っています。
望むらくは、このプロセスを効率的に進めて時短したいことですが、こういうのは中々時間短くできるものではないですね。