前提・実現したいこと
React RouterとFirebaseのAuthenticationを利用して、ユーザの認証機能を作成しようとしています。
ルーティングは以下のようになっており、ルートにアクセスしようとした際、ログイン済みならそのまま表示して、未ログインの場合は/login
にリダイレクトさせるという感じです。
App.jsx
jsx:App.jsx
1import React from 'react'; 2import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'; 3 4import Login from './Login'; 5import Auth from './Auth'; 6import Top from './Top'; 7import Page2 from './Page2'; 8import Page3 from './Page3'; 9 10const App = () => ( 11 <Router> 12 <Switch> 13 <Route exact path="/login" component={Login} /> 14 <Auth> 15 <Switch> 16 <Route exact path="/" component={Top} /> 17 <Route exact path="/page2" component={Page2} /> 18 <Route exact path="/page3" component={Page3} /> 19 </Switch> 20 </Auth> 21 </Switch> 22 </Router> 23); 24 25export default App;
Auth.jsx
ではコンポーネントがマウントされる前に、Firebase Authenticationを利用してユーザーのログイン状態をチェックしてstateを切り替え、表示するページを切り替えています。
Auth.jsx
jsx:Auth.jsx
1import firebase from 'firebase/app'; 2import React from 'react'; 3import PropTypes from 'prop-types'; 4import { Redirect } from 'react-router-dom'; 5 6export default class Auth extends React.Component { 7 constructor(props) { 8 super(props); 9 this.state = { 10 auth: false, 11 }; 12 } 13 14 componentWillMount() { 15 firebase.auth().onAuthStateChanged((user) => { 16 if (user) { 17 this.setState({ 18 auth: true, 19 }); 20 } 21 }); 22 } 23 24 render() { 25 if (!this.state.auth) { 26 return ( 27 <Redirect to="/login" /> 28 ); 29 } 30 return ( 31 this.props.children 32 ); 33 } 34} 35 36Auth.propTypes = { 37 children: PropTypes.object.isRequired, 38}; 39
未ログインの場合は/login
にリダイレクトされるのですが、ログインされている状態でlocalhost:8080/
とURLをブラウザに直打ちしてページを表示しようとすると、下記のような警告が表示され、/login
にリダイレクトされます。
componentWillMount()
の中で非同期処理が走っているため、setState()
よりも前にrender()
が呼び出され強制的にリダイレクトされてしまっている。その後、setState()
されてもコンポーネントが存在しないから、render()
も何もできない。
というのが原因だと考えています。
一番最初にも記述したように、
ルートにアクセスしようとした際、ログイン済みならそのまま表示して、未ログインの場合は
/login
にリダイレクトさせる
というのを実現するには同実装すればよいのでしょうか?
なにかご回答を頂けると助かります<(_ _)>
補足情報
ちなみに下記リンク先を参考にルーティングしました。
React-Router v4を使って認証状態でリダイレクトする処理
追記
よく考えたら、下記のようにしてloading
というstateを持たせてtrue
の時は return <p>Now loading...</p>;
みたいな感じで実装したらいいのですかね...
下記のようにしたら一応思った挙動にはなっているようなのですが、これがベストプラクティスかどうかはわからないので、まだ回答は募集します<(_ _)>
jsx:Auth.jsx
1// 略 2constructor(props) { 3 super(props); 4 this.state = { 5 auth: false, 6 loading: true, 7 }; 8 } 9 10// 略 11render() { 12 if (this.state.loading) { 13 return <p>Now loading...</p>; 14 } 15 if (!this.state.auth) { 16 return ( 17 <Redirect to="/login" /> 18 ); 19 } 20 return ( 21 this.props.children 22 ); 23 }
あなたの回答
tips
プレビュー