Wil*_*iam 17 javascript firebase reactjs firebase-authentication react-context
我正在编写一个使用Firebase进行身份验证的基本CRUD React应用程序.目前我正在尝试为名为Dashboard的组件创建受保护的路由.受保护的路由确保除非用户通过身份验证,否则任何封装的路由(例如仪表板)都不会呈现.如果用户未经过身份验证,则路由器会重定向到目标网页.
我完成此任务的方式是以这篇文章为蓝本的:
我已经模仿了上面文章中的模式,它工作正常.当我合并firebase(特别是firebase身份验证)时,即使用户已登录,我的应用也不会呈现仪表板组件.而只是重定向到登陆页面
我知道问题是什么(我认为),但我不确定如何解决它.
问题是对firebase的调用是异步操作,仪表板在解析对firebase的调用之前尝试加载.
我想知道他们是否可以修改我的代码.
每次用户加载受保护的路由(检查身份验证)时,我都可以对firebase进行api调用,但我更愿意在Context状态下设置身份验证并引用该状态,直到用户登录或注销为止.
我在下面放了相关代码.所有文件都在src目录中
谢谢!
App.js
import React, { Component } from 'react';
import { BrowserRouter, Route, Redirect } from "react-router-dom";
import {Switch} from 'react-router';
import Landing from './PageComponents/Landing';
import {Provider} from './PageComponents/Context';
import Dashboard from './PageComponents/Dashboard';
import ProtectedRoute from './PageComponents/ProtectedRoute';
class App extends Component {
render() {
return (
<div className="App">
<Provider>
<BrowserRouter>
<div>
<Switch>
<Route exact={true} path="/" component={Landing} />
<ProtectedRoute exact path="/dashboard" component={Dashboard} />
</Switch>
</div>
</BrowserRouter>
</Provider>
</div>
);
}
}
export default App;
Run Code Online (Sandbox Code Playgroud)
PageComponents/Context.js
import React from 'react';
import { getUser } from '../services/authentication';
let Context = React.createContext();
class Provider extends React.Component {
state = {
userID: true,
user:undefined,
authenticated:false
}
async getUser(){
try{
let user = await getUser();
return user
} catch(error){
console.log(error.message)
}
}
async componentDidMount(){
console.log("waiting to get user")
let user = await this.getUser();
console.log(user)
console.log("got user")
this.setState({
userID: user.uid,
user:user,
authenticated:true
})
}
render(){
console.log(this.state)
return(
<Context.Provider value={{
state:this.state
}}>
{this.props.children}
</Context.Provider>
)
}
}
const Consumer = Context.Consumer;
export {Provider, Consumer};
Run Code Online (Sandbox Code Playgroud)
PageComponents /仪表板
import * as React from 'react';
import {Consumer} from '../../PageComponents/Context';
class Dashboard extends React.Component {
render(){
console.log("Dashboard component loading....")
return(
<Consumer>
{(state)=>{
console.log(state)
return(
<div>
<p> Dashboard render</p>
</div>
)
}}
</Consumer>
)
}
}
export default Dashboard
Run Code Online (Sandbox Code Playgroud)
PageComponents/ProtectedRoute
import React from 'react';
import { Route, Redirect } from 'react-router-dom';
import { Consumer } from '../PageComponents/Context';
const ProtectedRoute = ({ component: Component, ...rest }) => {
console.log("Middleware worked!");
return (
<Consumer>
{(context)=>{
/*________________________BEGIN making sure middleware works and state is referenced */
console.log(context);
console.log("Middle ware");
/*________________________END making sure middleware works and state is referenced */
console.log( context.getState().authenticated + " <--- is authenticated from ProtectedRoute. true or false?")
if(context.state.authenticated){
return(
<Route {...rest} render={renderProps => {
console.log(renderProps);
return (<Component {...renderProps} />)
}}/>
)
}else{
return <Redirect to="/"/>
}
}}
</Consumer>
)
};
export default ProtectedRoute;
Run Code Online (Sandbox Code Playgroud)
服务/认证
import firebase from '../../services/firebase'
const getUser = () =>{
return new Promise((resolve, reject) => { // Step 3. Return a promise
//___________________ wrapped async function
firebase.auth().onAuthStateChanged((user)=> {
if(user){
resolve(user); //____This is the returned value of a promise
}else{
reject(new Error("Get user error"))
}
})
//_____________________END wrapped async function
});
}
export {getUser }
Run Code Online (Sandbox Code Playgroud)
Shu*_*tri 11
问题:您确实是正确的,API调用getUser是异步的并且被触发componentDidMount,因此在authentication设置时间状态时true,Redirect组件已经被触发.
解决方案:您需要等待身份验证请求成功,然后决定加载路由或重定向ProtectedRoute组件.
为了使其工作,您需要一个加载状态.
PageComponents/Context.js
let Context = React.createContext();
class Provider extends React.Component {
state = {
userID: true,
user:undefined,
loading: true,
authenticated:false
}
async getUser(){
let user = await getUser();
return user
}
async componentDidMount(){
console.log("waiting to get user")
try {
let user = await this.getUser();
console.log(user)
console.log("got user")
this.setState({
userID: user.uid,
user:user,
loading: false,
authenticated:true
})
} catch(error) {
console.log(error);
this.setState({
loading: false,
authenticated: false
})
}
}
render(){
return(
<Context.Provider value={{
state:this.state
}}>
{this.props.children}
</Context.Provider>
)
}
}
const Consumer = Context.Consumer;
export {Provider, Consumer}
Run Code Online (Sandbox Code Playgroud)
PageComponents/ProtectedRoute
import React from 'react';
import { Route, Redirect } from 'react-router-dom';
import { Consumer } from '../PageComponents/Context';
const ProtectedRoute = ({ component: Component, ...rest }) => {
console.log("Middleware worked!");
return (
<Consumer>
{(context)=>{
/* BEGIN making sure middleware works and state is referenced */
console.log(context);
console.log("Middle ware");
/* END making sure middleware works and state is referenced */
console.log( context.getState().authenticated + " <--- is authenticated from ProtectedRoute. true or false?")
// Show loading state
if (context.state.loading) {
return <Loader />
}
if(context.state.authenticated){
return(
<Route {...rest} render={renderProps => {
console.log(renderProps);
return (<Component {...renderProps} />)
}}/>
)
}else{
return <Redirect to="/"/>
}
}}
</Consumer>
)
};
export default ProtectedRoute;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
588 次 |
| 最近记录: |