导入
使用 Firebase 和 React 进行会话管理
本节将介绍我们的 React 应用在用户成功登录后如何管理用户会话。
本节课对于认证流程至关重要。由于我们在 React 中已经具备完成认证完整流程的所有组件,现在唯一缺少的就是一个“监管者”来监控和检查会话状态。
当前已认证用户的信息需要被存储,并可供其他组件访问。这正是开发者最常开始使用像 Redux 或 MobX 这样的状态管理库的地方。在本课程中,我们将通过使用全局状态来实现,而不依赖专门的状态管理库。
由于我们的应用始终在 App 组件 的框架下构建,因此只需在 App 组件中使用 React 的本地状态来管理会话状态即可。App 组件只需跟踪一个已认证的用户(会话)。
App 组件与会话状态
当用户已认证(即成功登录应用)时,我们将在本地状态中存储该用户信息,并将其对象向下传递给所有可能需要使用它的组件;若用户未认证,则向下传递 null。这样,所有关心该信息的组件都可以根据会话状态调整自身行为(例如使用条件渲染)。
例如,Navigation 组件就对此感兴趣,因为它需要为已认证和未认证的用户显示不同的选项。另一个例子是,SignOut 组件不应出现在未认证用户的界面上(即尚未登录的用户)。
### 实现 我们将在 `src/components/App/index.js` 文件中的 App 组件内实现**会话处理**。由于该组件现在需要管理本地状态,因此需将其重构为类组件,用于管理 `authUser` 对象的本地状态,并将该用户信息传递给 **Navigation 组件**。 ```javascript import React, { Component } from 'react'; import { BrowserRouter as Router, Route } from 'react-router-dom'; ... class App extends Component { constructor(props) { super(props); this.state = { authUser: null, }; } render() { return ( <Router> <div> <Navigation authUser={this.state.authUser} /> <hr/> ... </div> </Router> ); } } export default App; ``` #### 基于认证状态的导航 **Navigation 组件**可以通过接收 `authUser` 来感知当前用户是否已认证,从而决定显示哪些链接。它应仅展示对已认证用户或未认证用户可用的选项。 ```javascript import React from 'react'; import { Link } from 'react-router-dom'; import SignOutButton from '../SignOut'; import * as ROUTES from '../../constants/routes'; const Navigation = ({ authUser }) => ( <div>{authUser ? <NavigationAuth /> : <NavigationNonAuth />}</div> ); const NavigationAuth = () => ( <ul> <li> <Link to={ROUTES.LANDING}>首页</Link> </li> <li> <Link to={ROUTES.HOME}>主页</Link> </li> <li> <Link to={ROUTES.ACCOUNT}>账户</Link> </li> <li> <SignOutButton /> </li> </ul> ); const NavigationNonAuth = () => ( <ul> <li> <Link to={ROUTES.LANDING}>首页</Link> </li> <li> <Link to={ROUTES.SIGN_IN}>登录</Link> </li> </ul> ); export default Navigation; ``` 现在让我们看看 App 组件中的 `authUser`(已认证用户)从何而来。Firebase 提供了一个**监听函数**,可用于从 Firebase 获取已认证用户。 #### Firebase 监听器 ```javascript ... import * as ROUTES from '../../constants/routes'; import { withFirebase } from '../Firebase'; class App extends Component { constructor(props) { super(props); this.state = { authUser: null, }; } componentDidMount() { this.props.firebase.auth.onAuthStateChanged(authUser => { authUser ? this.setState({ authUser }) : this.setState({ authUser: null }); }); } ... } export default withFirebase(App); ``` ### 说明 `onAuthStateChanged()` 这个辅助函数接收一个函数作为参数,该函数可访问当前已认证的用户。每当用户状态发生变化时,此函数都会被调用。它会在用户注册、登录或登出时触发。当用户登出时,`authUser` 对象变为 `null`,此时本地状态中的 `authUser` 属性也会被设为 `null`,所有依赖该状态的组件便会相应调整其行为(例如,Navigation 组件会显示不同的选项)。 此外,为了避免内存泄漏导致的**性能问题**,我们还需要在组件卸载时移除该监听器。 ```javascript ... class App extends Component { ... componentDidMount() { this.listener = this.props.firebase.auth.onAuthStateChanged( authUser => { authUser ? this.setState({ authUser }) : this.setState({ authUser: null }); }, ); } componentWillUnmount() { this.listener(); } ... } export default withFirebase(App); ``` 启动应用,验证注册、登录和登出功能是否正常工作,同时确认 Navigation 组件能根据会话状态正确显示不同选项,即根据用户是否已认证来渲染不同的界面。恭喜,我们已成功在 React 应用中使用 Firebase 实现了认证流程。下一节课我们将运行并验证这一功能。