如何将用户状态默认为登录用户Firebase和React



我刚刚用React和Firebase在我的web应用程序中实现了身份验证。它工作得很好,但我意识到,对于每次页面更改或刷新,它首先将状态默认为null用户。AuthChangeListener会立即启动并检测到有什么东西登录并重新发送屏幕。我知道这就是React的工作方式,但我如何将当前用户状态默认为当前登录的用户。到目前为止,它看起来像是在快速闪烁。

export default class Router extends Component {
constructor(props)
{
super(props);
this.state = {
user:null
}
this.login = this.login.bind(this);
this.logout = this.logout.bind(this);
}
authListener()
{
// fetch current user
auth.onAuthStateChanged((user) => {
if (user) {
this.setState({
user:user
});
}
else {
this.setState({
user:null
});
}
});
}
componentDidMount()
{
this.authListener();
}
render()
{
return(
<BrowserRouter>
<Switch>
<Route exact path="/donate" component = {() => <Donate user={this.state.user} />}/>
<Route exact path="/" component = {() => <Donate user={this.state.user} />}/>
<Route exact path="/news" component = {News}/>
<Route exact path="/about" component = {About}/>
<Route exact path="/auth" component = {() => <Auth user={this.state.user} login={this.login} logout={this.logout}/>}/>
<Route exact path="/funded" component = {Funded}/>
<Route exact path="/contact" component = {Contact}/>
<Route path="*" component={Error} />
</Switch>
</BrowserRouter>
)
}
}

我记得遇到过这样的事情。不幸的是,当会话状态发生变化(用户登录/注销(时,onAuthStateChanged会执行操作,但它不会告诉您是否存在活动会话。

我发现处理它的唯一方法是用重复计时器检查currentUser属性,并将状态属性设置为false,直到结果返回null或在多次尝试后返回当前会话。当计时器运行时,我在屏幕上有一个覆盖和一个旋转计时器,让用户知道应用程序正在工作。如果结果为null,则没有用户会话,显示登录表单。如果活动会话返回,则显示相应的组件。

constructor(){
super();
this.state = { sessionChecks: 0 };
this.auth = firebase.auth();
this.checkActiveUser = this.checkActiveUser.bind(this);
}
checkActiveUser(){
const loggedUser = this.auth.currentUser;
// set this to the amount of tries you want
if( !loggedUser && this.state.sessionChecks < 3) {
setTimeout( () => {
// no user session, check again
this.setState({ sessionChecks: ( sessionChecks + 1 ) });
this.checkActiveUser();
}, 500); // change the time to what you want
} else if(loggedUser) {
// there is an active user, run your code here
}
}

另一个仍然需要使用计时器检查用户会话的选项是使用currentUserreload方法,该方法返回一个可以在异步代码中使用的承诺:

https://firebase.google.com/docs/reference/js/firebase.User?authuser=0#reload


编辑

为了只检查一次用户会话,我想出的解决方案是创建一个包含所有路由的组件,并将该组件添加到主应用程序文件中。

这是主应用程序文件(index.js(

const App = => <Provider store={appStore}>
<Router>
<Routes />
</Router>
</Provider>;

App被传递给ReactDOM的呈现方法。路由器是浏览器像这样导入的路由器:import { BrowserRouter as Router } from "react-router-dom";。路由是所有路由的组成部分。该组件在应用程序的生命周期中只安装一次。

这里是<Routes />组件(至少是它的相关部分(:

constructor(){
super();
this.state = {
sessionChecks: 0,
currentUser: null
};
this.renderRoute = this.renderRoute.bind(this);
this.checkActiveUser = this.checkActiveUser.bind(this);
this.authSession = firebase.auth();
}
checkActiveUser() {
const { sessionChecks } = this.state;
const loggedUser = this.authSession.currentUser;
// check for the loggedUser
if ( !loggedUser && sessionChecks < 3 ) {
setTimeout(
() => {
this.setState({ sessionChecks: ( sessionChecks + 1 ) });
this.checkActiveUser();
},
500
);
} else if ( loggedUser ){
// in this check there is a logged user
// update the component's state, this will force a render
// and the corresponding component will be rendered
this.setState({ currentUser: true });
}
}
renderRoute(component){
// if the current user is null means we're still checking
// so we check strictly true
if ( this.state.currentUser === true ) {
// the check is complete and there's an active user, show the component
return component;
} else if ( !this.state.currentUser ) {
// the check is complete and there isn't an active user
// show a login component 
return <LoginComponent />;
}
}
render(){
return <div>
<Route path="/" exact render={ () => this.renderRoute(<DashboardComponent />) } />
<Route path="/tags" render={ () => this.renderRoute(<TagsComponent />) } />
<Route path="/posts" render={ () => this.renderRoute(<PostsComponent />) } />
<Route path="/programs" render={ () => this.renderRoute(<ProgramsComponent />) } />
</div>;
}

现在,在代码检查时,您可以在登录组件上显示一个带有微调器和消息的覆盖,而不是一直显示登录组件。当检查完成时,无论是否有活动会话,都可以隐藏该覆盖并显示呈现的组件,无论是登录组件还是特定路由的组件。

希望这能有所帮助。

最新更新