惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

F
Full Disclosure
Stack Overflow Blog
Stack Overflow Blog
H
Help Net Security
Microsoft Azure Blog
Microsoft Azure Blog
The GitHub Blog
The GitHub Blog
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Recorded Future
Recorded Future
Y
Y Combinator Blog
Cloudbric
Cloudbric
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
S
Schneier on Security
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
C
Cybersecurity and Infrastructure Security Agency CISA
TaoSecurity Blog
TaoSecurity Blog
Security Latest
Security Latest
N
News and Events Feed by Topic
Hacker News - Newest:
Hacker News - Newest: "LLM"
D
DataBreaches.Net
Security Archives - TechRepublic
Security Archives - TechRepublic
H
Hacker News: Front Page
C
Cisco Blogs
L
LangChain Blog
aimingoo的专栏
aimingoo的专栏
Recent Commits to openclaw:main
Recent Commits to openclaw:main
V
Vulnerabilities – Threatpost
L
LINUX DO - 最新话题
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Google Online Security Blog
Google Online Security Blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
A
About on SuperTechFans
www.infosecurity-magazine.com
www.infosecurity-magazine.com
Jina AI
Jina AI
C
CXSECURITY Database RSS Feed - CXSecurity.com
Schneier on Security
Schneier on Security
T
Tenable Blog
N
News and Events Feed by Topic
W
WeLiveSecurity
有赞技术团队
有赞技术团队
AI
AI
爱范儿
爱范儿
大猫的无限游戏
大猫的无限游戏
Latest news
Latest news
T
The Blog of Author Tim Ferriss
S
Security Affairs
Know Your Adversary
Know Your Adversary
Simon Willison's Weblog
Simon Willison's Weblog
G
GRAHAM CLULEY
Google DeepMind News
Google DeepMind News
The Cloudflare Blog

Kent C. Dodds Blog

Implementing Hybrid Semantic + Lexical Search Simplifying Containers with Cloudflare Sandboxes Migrating to Workspaces and Nx Offloading FFmpeg with Cloudflare Building Semantic Search on my Content Helping YOU ask ME questions with AI How I used Cursor to Migrate Frameworks The Dow's Start on the Covenant Path 2025 in Review The next chapter: EpicAI.pro AI is taking your job How I increased my visibility Launching Epic Web 2023 in Review Stop Being a Junior RSC with Dan Abramov and Joe Savona Live Stream Fixing a Memory Leak in a Production Node.js App 2022 in Review My Car Accident I Migrated from a Postgres Cluster to Distributed SQLite with LiteFS I'm building EpicWeb.dev A review of my time at Remix Remix: The Yang to React's Yin How I help you build better websites Why I Love Remix The State Initializer Pattern How to React ⚛️ Get a catch block error message with TypeScript Building an awesome image loading experience How Remix makes CSS clashes predictable Introducing the new kentcdodds.com How I built a modern website in 2021 How to use React Context effectively Static vs Unit vs Integration vs E2E Testing for Frontend Apps The Testing Trophy and Testing Classifications Array reduce vs chaining vs for loop Don't Solve Problems, Eliminate Them Super Simple Start to Remix Super Simple Start to ESModules in Node.js JavaScript Pass By Value Function Parameters How to write a Constrained Identity Function (CIF) in TypeScript How to optimize your context value How to write a React Component in TypeScript TypeScript Function Syntaxes Listify a JavaScript Array Build vs Buy: Component Libraries edition Using fetch with TypeScript Wrapping React.useState with TypeScript Define function overload types with TypeScript 2020 in Review Business and Engineering alignment Hi, thanks for reaching out to me 👋 useEffect vs useLayoutEffect Super simple start to Firebase functions Super simple start to Netlify functions Super Simple Start to css variables Favor Progress Over Pride in Open Source Testing Implementation Details How getting into Open Source has been awesome for me useState lazy initialization and function updates Use ternaries rather than && in JSX Application State Management with React Use react-error-boundary to handle errors in React JavaScript to Know for React How I structure Express apps What open source project should I contribute to? When I follow TDD AHA Programming 💡 How I Record Educational Videos Should I write a test or fix a bug? Stop mocking fetch Intentional Career Building Improve test error messages of your abstractions Tracing user interactions with React Eliminate an entire category of bugs with a few simple tools Common mistakes with React Testing Library Super Simple Start to React Stop using client-side route redirects The State Reducer Pattern with React Hooks Function forms Replace axios with a simple custom fetch wrapper How to test custom React hooks React Production Performance Monitoring Should I useState or useReducer? Stop using isLoading booleans Make Your Test Fail Make your own DevTools An Argument for Automation Fix the "not wrapped in act(...)" warning Super Simple Start to ESModules in the Browser Implementing a simple state machine library in JavaScript 2010s Decade in Review Why users care about how you write code Why I avoid nesting closures Don't call a React function component Why your team needs TestingJavaScript.com Inversion of Control Understanding React's key prop How to Enable React Concurrent Mode Profile a React App for Performance
Authentication in React Applications
2019-05-20 · via Kent C. Dodds Blog

Watch "Organization of Authentication State in React Apps" on egghead.io

Skipping to the end

Here's the secret to this blog post in one short code example:

import * as 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

That's it. Most apps which require authentication of any kind can be drastically simplified by that one little trick. Rather than trying to do something fancy to redirect the user when they happen to land on a page that they're not supposed to, instead you don't render that stuff at all. Things get even cooler when you do this:

import * as 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

Sweet, now you don't even bother loading the code until it's needed. So the login screen shows up faster for unauthenticated users and the app loads faster for authenticated users.

What the <AuthenticatedApp /> and <UnauthenticatedApp /> do is totally up to you. Maybe they render unique routers. Maybe they even use some of the same components. But whatever they do, you don't have to bother wondering whether the user is logged in because you make it literally impossible to render one side of the app or the other if there is no user.

How do we get here?

If you want to just look at how it's all done, then you can checkout the bookshelf repo which I made for my Build ReactJS Applications Workshop.

Ok, so what do you do to get to this point? Let's start by looking at where we're actually rendering the app:

import * as React from 'react'
import ReactDOM from 'react-dom'
import App from './app'
import AppProviders from './context'

ReactDOM.render(
	<AppProviders>
		<App />
	</AppProviders>,
	document.getElementById('root'),
)

And here's that <AppProviders /> component:

import * as 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, cool, so we have a provider from the app's authentication and one for the user's data. So presumably the <AuthProvider /> would be responsible for bootstrapping the app data (if the user's authentication token is already in localStorage then we can simply retrieve the user's data using that token). Then the <UserProvider /> would be responsible for keeping the user data up to date in memory and on the server as we make changes to the user's data (like their email address/bio/etc.).

The auth-context.js file has some stuff in it that's outside the scope of this blog post/domain specific, so I'm only going to show a slimmed down/modified version of it:

import * as React from 'react'
import { FullPageSpinner } from '#app/components/lib'

const AuthContext = React.createContext()

function AuthProvider(props) {
	// code for pre-loading the user's information if we have their token in
	// localStorage goes here

	// 🚨 this is the important bit.
	// Normally your provider components render the context provider with a value.
	// But we post-pone rendering any of the children until after we've determined
	// whether or not we have a user token and if we do, then we render a spinner
	// while we go retrieve that user's information.
	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

	// note, I'm not bothering to optimize this `value` with React.useMemo here
	// because this is the top-most component rendered in our app and it will very
	// rarely re-render/cause a performance problem.
	return (
		<AuthContext.Provider
			value={{ data, login, logout, register }}
			{...props}
		/>
	)
}

const useAuth = () => React.useContext(AuthContext)

export { AuthProvider, useAuth }

// the UserProvider in user-context.js is basically:
// const UserProvider = props => (
//   <UserContext.Provider value={useAuth().data.user} {...props} />
// )
// and the useUser hook is basically this:
// const useUser = () => React.useContext(UserContext)

The key idea that drastically simplifies authentication in your app is this:

The component which has the user data prevents the rest of the app from being rendered until the user data is retrieved or it's determined that there is no logged-in user

It does this by simply returning a spinner instead of rendering the rest of the app. It's not rendering a router or anything at all really. Just a spinner until we know whether we have a user token and attempt to get that user's information. Once that's done, then we can continue with rendering the rest of the app.

Conclusion

Many apps are different. If you're doing server-side rendering then you probably don't need a spinner and you have the user's information available to you by the time you start rendering. Even in that situation, taking a branch higher up in the tree of your app drastically simplifies the maintenance of your app.

If you want to play around with a really simple version of this, open up this codesandbox:

Edit React App Auth

I hope this is helpful to you. You can checkout the bookshelf repo (or even edit it on codesandbox) for a more complete picture of what all this is like in a more realistic scenario with all the pieces together.

Authentication Course

My friend Ryan Chenckie made a course all about react authentication and security that I think you'll love. Check out his React Security Course.

P.S.

Several people have asked me: What if my app has lots of shared screens between authenticated and unauthenticated users (like Twitter) rather than having very different screens between authenticated and unauthenticated users (like Gmail)?

In that case then you'll probably need to litter a bunch of useUser() hooks all over the codebase. You might make it even easier with a useIsAuthenticated() hook that simply returns a boolean if the user is logged in. Either way, it's pretty simple thanks to context + hooks :)