[譯]React中的用戶認證(登陸態管理)

[譯]React中的用戶認證(登陸態管理)

原文地址kentcdodds.com/blog/authen…javascript

本文主要展現在當下 React 應用開發中,怎麼使用 ContextHooks 來管理用戶的認證(也就是登陸態)。java

先說結論

下面是本文最終要實現的的簡化版,方便大佬們直接看最後的效果:react

import React from 'react'
import {useUser} from './context/auth'
import AuthenticatedApp from './authenticated-app'
import UnauthenticatedApp from './unauthenticated-app'
function App() {
  const user = useUser()
  return user ? <AuthenticatedApp /> : <UnauthenticatedApp /> } export App 複製代碼

嗯,最終的代碼大概就長這樣。大多數 須要進行用戶認證管理的應用,均可以使用相似上面的邏輯來管理用戶登陸狀態。當用戶訪問咱們應用中的某個須要登陸後才能訪問的頁面時,咱們能夠將用戶重定向到登錄頁,大多數狀況下也是這樣作的,除此以外,咱們還能夠不進行跳轉,直接在該頁面上展現未登陸用戶看到的界面。爲了提升用戶體驗,咱們也能夠這樣:git

import React from 'react'
import {useUser} from './context/auth'
const AuthenticatedApp = React.lazy(() => import('./authenticated-app'))
const UnauthenticatedApp = React.lazy(() => import('./unauthenticated-app'))
function App() {
  const user = useUser()
  return user ? <AuthenticatedApp /> : <UnauthenticatedApp /> } export App 複製代碼

親,代碼 懶加載 就實現了:未登陸用戶訪問咱們頁面,只會加載渲染未登陸界面的代碼;已登陸用戶訪問同一個頁面,一樣只會加載渲染已登陸界面的代碼。github

具體在 AuthenticatedAppUnauthenticatedApp 裏渲染什麼界面,徹底是開發者來決定。或許他們會渲染一些 router ,甚至會複用一些公共組件。不管具體渲染什麼,咱們都不用關心用戶的登陸態了,由於在渲染這兩個組件之一的時候,已經明確知道了用戶的登陸狀態。後端

怎麼一步步實現上面的邏輯

若是你想看看最終整個APP的實現,能夠到 這個github 查看。服務器

OK,咱們接下來看看怎麼一步步來實現上面的邏輯。首先,咱們看下咱們應用的入口代碼:app

import React from 'react'
import ReactDOM from 'react-dom'
import App from './app'
import AppProviders from './context'
ReactDOM.render(
  <AppProviders> <App /> </AppProviders>,
  document.getElementById('root'),
)
複製代碼

下面是 AppProviders組件的代碼:dom

import React from 'react'
import {AuthProvider} from './auth-context'
import {UserProvider} from './user-context'
function AppProviders({children}) {
  return (
    <AuthProvider> <UserProvider>{children}</UserProvider> </AuthProvider>
  )
}
export default AppProviders
複製代碼

OK,咱們有兩個 Provider: 一個是維護應用的認證狀態;另外一個是維護當前登陸用戶的數據。按照字面意思,AppProvider 負責初始化整個APP的數據(若是在localStorage中存在用戶認證後的token,那麼咱們能夠直接從token中獲取一些用戶數據)。另外一方面,UserProvider負責將咱們對用戶數據的一些修改(好比email地址、履歷等)保持和服務器端的同步。ide

完整的auth-context.js 包含一些和本文主題無關的邏輯,所以下面咱們來看下簡化版的 auth-context.js

import React from 'react'
import {FullPageSpinner} from '../components/lib'
const AuthContext = React.createContext()
function AuthProvider(props) {
  // 若是咱們還不肯定當前用戶是否登陸,好比還在請求後端接口查詢登陸狀態,
  // 那麼咱們就渲染一個全局的加載中,而不是加載真正的頁面組件
  if (weAreStillWaitingToGetTheUserData) {
    return <FullPageSpinner />
  }
  const login = () => {} // make a login request
  const register = () => {} // register the user
  const logout = () => {} // clear the token in localStorage and the user data
 
  // 注意:這裏我並無使用 `React.useMemo` 來優化 provider 的 `value`。
  // 由於這是咱們應用裏最頂級的組件,不多會在這個頂級組件上觸發 從新render
  return (
    <AuthContext.Provider value={{data, login, logout, register}} {...props} />
  )
}
const useAuth = () => React.useContext(AuthContext)
export {AuthProvider, useAuth}
// user-context.js 文件裏的 `UserProvider` 大概長這樣:
// const UserProvider = props => (
//   <UserContext.Provider value={useAuth().data.user} {...props} />
// )
// and the useUser hook is basically this:
// const useUser = () => React.useContext(UserContext)
複製代碼

簡化咱們應用裏的認證管理的關鍵點是:

負責維護用戶登陸態的組件,在獲取到當前用戶的登陸狀態以前,不會渲染頁面的主體內容,能夠渲染一個加載中的全局loading。只有當從服務器端獲取到用戶的登陸狀態以後,纔去渲染頁面的主體:已登陸就渲染登陸後的組件;未登陸渲染未登陸的。

結論

在實際開發中,不少APP面臨的場景都是不一樣的。若是你採用了服務端渲染技術(SSR),那麼你極可能不須要一個加載中的loading,由於你在服務端已經明確知道了,當前用戶是否已登陸。即便在這個場景下,一樣能夠將用戶的登陸狀態提出到全局的 Provider 來管理,這樣會加強咱們代碼的可維護性。

PS

有些同窗問到了相同的問題:若是咱們的應用,已登陸用戶和未登陸用戶看到的不少界面都相同(好比twitter),而不是像gmail那樣,已登陸用戶和未登陸用戶看到的徹底不一樣,咱們應該怎麼來維護用戶登陸狀態呢?

若是是這種狀況,那麼代碼裏不少組件,都會用到 useUser這個hook,爲了能在一個公共組件中,根據是否登陸而執行不一樣邏輯。由於咱們的公共組件可能值關心用戶是否登陸,你甚至能夠再封裝出一個 useIsAuthenticated hook,返回一個 boolean 值,表示當前用戶是否已登陸。多虧了 ContextHooks,要實現這樣的邏輯很是的簡單。

相關文章
相關標籤/搜索