はじめに
現在実装中のポートフォリオでは、react router domを使用してフロント側のルーティングを制御しています。
ネットの記事を参考にする中で、react router domがルーティングを照合する精度の違いを理解していなかったことで詰まった部分があったので、備忘録として残します。
環境
react 18.0.0
react router dom 5系
rails 6.1.4
M1mac
前提
devise_token_authでユーザーのログイン機能を作っており、ログイン前に入れない/そもそも存在しないURLに移動しようとするとサインインの画面に自動で移動するように設定しています。
何に困ったのか
devise_token_authでログイン前にパスワードを忘れた時のために、メールアドレスをフォームに入力すれば、パスワード変更用のリンクがメールに送られてきて、そのリンクからパスワードを変更できる機能を作成していた時にルーティングの精度が原因で詰まったので、その内容も備忘録として記載します。
パスワード変更の機能を作るために、メールから移動できるredirect_urlを指定し、しっかり求めている画面が表示されるように、下記のようにルーティングも設定しました。
<Route exact path="password/reset/form" component={パスワード再設定用の画面} />
URLを直で打ってみるとちゃんと表示されることも確認できます。
しかし、上記のように送られてきたメールのリンクを押して移動をすると、パスワード再設定画面ではなく、サインイン画面に移動してしまいます。
原因はURLにパロメータがついていたからだった
少し話はずれますが、ログイン前にパスワードを変更するには、"ログインしてないけどパスワードを変更してOKになるパスワード的なもの(reset password tokenとか、accsess-tokenとかのトークン)"が必要です。
そのパスワード的なものが下記のような形で付属されているリンクがメールに貼り付けられてきます。
パスワードを変更する画面のURL + パロメータ(これがパスワード的なもの)
//こんな感じ。"~form?"までがパスワード変更画面のURL(pwで隠している部分にトークンが入ります)
http://localhost:4000/api/v1/auth/password/reset/form?access-token=[pw]
&client=[pw]&client_id=[pw]&config=default&expiry=[pw]&reset_password=true&token=[pw]&uid=[pw]
メールから送られてくるリンクに"ログインしてないけどパスワードを変更してOKになるパスワード的なもの(reset password tokenとか、accsess-tokenとか)"がURLのパロメータとしてくっついて帰ってきます。
ルーティングの記述を修正
サインインの画面に移動してしまう原因は、先ほど下記のように記述したルーティングの設定の箇所です。
<Route exact path="password/reset/form" component={パスワード再設定用の画面} />
この"exact"という文言がついていると、"URLが完全一致した場合にコンポーネントを表示する"ということになります。
一文字でも間違っていると表示されないということです。
"Route path"のみで何もついていないと、前方一致が指定ればOKです。それ以降何か文字がたされていても画面を表示してくれます。
//password/reset/form以降に何か文字が入っていると表示されない
//password/reset/form?~だともちろん表示されないのでサインインの画面に移動する
<Route exact path="password/reset/form" component={パスワード再設定用の画面} />
//password/reset/form以降に文字が入っていても、formまでが一致していれば表示される
//form?~(パスワード変更に必要なパラメータ)が付属していてもコンポーネントは表示される
<Route path="password/reset/form" component={パスワード再設定用の画面} />
ちなみに
"sensitive"をつけると大文字・小文字も厳格にチェックする、などの条件を追加できます。
前方一致がデフォルトの機能だったのでちゃんと理解して使っていれば普通にオプションを加えることはないので問題なかったと思うのですが、
react-router-domを全く理解せずにとりあえずネットの記事を真似てコードを書いていたあの頃は気づけなくて当たり前だと思うので仕方ないなと割り切っています。
今回知れてよかった。
ちなみに、無事exactを外して前方一致がするように修正をしたら問題なくメールからパスワード再設定画面を表示させることができました。
<Route path="/api/v1/auth/password/reset/form" component={RedirectForgetPassword} />
終わりに
ここだけの話今回の画面移動できないエラーよりも、URLのパラメータを使ってどうやってパスワードを変更するのかというロジックを記述する方が体力使った気がします。。
今さっきなんとか完成できたので達成感半端ないです。。
リファクタリングもできたら頭の整理も兼ねてqiitaに書こうかなと思います。
理解不足でも手を動かしながら学んでいるので、間違った解釈の部分があるかもしれません。
もしそのような場所があったら優しくご指摘いただけますと幸いです。