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

推荐订阅源

L
Lohrmann on Cybersecurity
Martin Fowler
Martin Fowler
Engineering at Meta
Engineering at Meta
腾讯CDC
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Microsoft Azure Blog
Microsoft Azure Blog
G
Google Developers Blog
TaoSecurity Blog
TaoSecurity Blog
博客园_首页
Vercel News
Vercel News
Hugging Face - Blog
Hugging Face - Blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Last Week in AI
Last Week in AI
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
T
The Exploit Database - CXSecurity.com
量子位
Project Zero
Project Zero
A
Arctic Wolf
小众软件
小众软件
NISL@THU
NISL@THU
C
CERT Recently Published Vulnerability Notes
有赞技术团队
有赞技术团队
MongoDB | Blog
MongoDB | Blog
博客园 - 聂微东
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
N
News and Events Feed by Topic
宝玉的分享
宝玉的分享
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
T
Troy Hunt's Blog
P
Privacy & Cybersecurity Law Blog
Security Latest
Security Latest
B
Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
D
DataBreaches.Net
Schneier on Security
Schneier on Security
The Hacker News
The Hacker News
K
Kaspersky official blog
C
Check Point Blog
Hacker News: Ask HN
Hacker News: Ask HN
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Webroot Blog
Webroot Blog
www.infosecurity-magazine.com
www.infosecurity-magazine.com
人人都是产品经理
人人都是产品经理
AI
AI
Cisco Talos Blog
Cisco Talos Blog
MyScale Blog
MyScale Blog
Cloudbric
Cloudbric
B
Blog RSS Feed
S
Schneier on Security
P
Palo Alto Networks 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 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 How to add testing to an existing project Profile a React App for Performance
Remix: The Yang to React's Yin
2022-03-24 · via Kent C. Dodds Blog

I've been building React applications since 2015. Since then, React was the biggest single productivity boost for my development by a long shot. React's declarative model for rendering UI based on state drastically simplified the way I thought about building UIs for the web. It also gave me a great way to think about state that was miles ahead of what I had been doing with Angular.js and Backbone before it.

React's tagline is:

A JavaScript library for building user interfaces

React does an excellent job of this by giving you that declarative component model it pioneered. You can't build a user interface without managing some state (is the combobox menu open or closed?). This is why React has component state management.

The trick is that there's a lot more to Web applications than local component state. In fact, the vast majority of the "state" loaded in the typical React application is not state at all, but a cache of state that came from the server (which it probably got from a persistence layer like a database for example). While React has always given us a nice way to manage state, it can't hide the fact that much of the state we're managing is actually a cache and suffers from the problems of caching.

As Phil Karlton's famous quote states:

There are only two hard things in Computer Science: cache invalidation and naming things.

In many ways this is a joke, but cache invalidation is definitely a challenging problem. And up to this point, React hasn't given us anything out of the box for managing this problem, as evidenced by the myriad of libraries and tools that have been built around React to make this easier. Whether you're using Redux (toolkit), MobX, Apollo, React Query, SWR, or something else, you're only reaching for those tools because there's a common, shared problem in web development that React doesn't have a built-in answer for:

Management of the Network Chasm

What's the network chasm?

Here's what I mean by the network chasm:

Excalidraw diagram showing a box labeled client and a box labeled server with the words "Network Chasm" between them

As web developers, we get to write code that runs in the client (the browser) and the server. We don't get any control over the network. This is why we have to think about caching in the first place. When our React component re-renders as the user makes their taco selection 🌮 we need to have synchronous access to the options available for that particular taco 🤤. So we make HTTP requests over the network, and store those values in an in-memory cache via React state (or some library) so they're available for our re-render.

Do you know the number one cause of bugs in apps both large and small?

Code.

That network chasm is the source of an enormous amount of code. Getting it right is extremely difficult, but we're building web apps, so we have to try. So, using the power of JavaScript, the modern fetch API, and some handy dandy libraries, we shoot a grappling hook over the network chasm via HTTP to get data to and from the backend:

Similar diagram as above with a box above "Client" that says "SPA" and an arrow from that over the network chasm pointing to a box that says "Node/Rails/PHP/Java/.Net". The row is labeled "Client-side apps"

The code required for this grappling hook to work all exists on the frontend. For data fetching, you have to know what data to fetch, and often that's a challenging problem because we like to co-locate our data fetching with the code that requires the data (reduces bugs/mistakes/data overfetching a great deal by doing things this way). This has the unfortunate side-effect of not being able to fetch data until the components have rendered.

Add to that the desire to implement code-splitting to make our app load faster, and now you have to not only wait for the component to render, but once it starts rendering you have to fetch the code that does the fetching too. This leads to network waterfalls (and we all know about the danger of waterfalls).

Unfortunately, data fetching by itself can't solve this problem. In fact, even React Suspense for Data fetching won't be able to solve this problem. Suspense will take the place of many data fetching libraries in being able to get the data from within the components (and if it's not cached yet it'll trigger the data to be fetched which is so fetch), but if you want to avoid the waterfall effect, you've got to start fetching the data before the code for those components are rendered.

Fetching Sooner

This is why I'm so excited that React Router is going to solve this problem by bringing much of what I love about Remix into React Router. Ryan explains this in his post Remixing React Router. With the power of layout nested routes and loaders (getting data) and actions (mutating data), you can decouple the data fetching from the components, but still benefit a lot from colocation. The fetching code might not be inside the component in this case, but because of the nature of nested layout routes, it's pretty darn close.

With these features, we go from "I have to render to know data requirements" to "I know data requirements from the URL."

On top of this, React Router is now managing some of that network chasm for you, meaning you have much less of your own code that has to worry about loading/error states. It also means that React Router can handle cache revalidation for you! Oh, and form resubmissions and race conditions too (some of the more challenging problems in UI development). And building excellent user experiences (like optimistic UI patterns) has never been easier. This effectively narrows the network chasm for you a bit:

Similar diagram as before except now the SPA box extends slightly further over the network chasm and the row is labeled "Remixed Router apps"

Can we do better?

Having those features within React Router will be a huge benefit for anyone looking to simplify their code and speed up their app. React Router will be a best friend for anyone using React Suspense for Data Fetching (unless you have the infrastructure/compiler/router that Meta has I suppose).

But we can do even better. Even once you start fetching from the browser earlier, your users still have to wait for the initial JavaScript bundles to show up and execute before they can see anything. With React Router helping you with managing the loading and mutation of data, you can delete a lot of state (cache) management code, but it's still all there in the browser. On top of that, because we need the code to do the fetching before we get the code that needs the fetched data it means that code isn't code-split anymore.

Wouldn't it be great, if we could just move all of that code out of the browser and onto the server? Isn't it annoying to have to write a serverless function any time you need to talk to a database or hit an API that needs your private key? (yes it is). These are the sorts of things React Server Components promise to do for us, and we can definitely look forward to that for data loading, but they don't do anything for mutations and it'd be cool to move that code out of the browser as well (and not have to wait for it to be released).

Enter stage right: Remix 💿

To really take your app to the next level, you'll want to server render your app. And the best way to do that is to use Remix. Remix finishes the bridge across the network boundary for you in such a way that you don't even have to think about it. You take all your data fetching and data mutation code and move it to be exported functions from conventional "Remix route modules" and all of a sudden all of that code stays on the server and Remix handles the entire network chasm for you:

Similar to the diagrams before with the addition of a "Backend for frontend" row that shows Remix spanning over the client and network boundary into the Server and an arrow pointing to "Rails/PHP/Java/.Net"

Now your app can really fly ⚡ because the user no longer has to wait for the JavaScript to load. The app is there and ready for them (and thanks to progressive enhancement, all the links and forms will work while the JavaScript downloads in the background too).

And get this, because now you can write code that runs on the server, you don't have to worry about making direct database calls or hitting APIs with private keys anymore. Your loaders and actions only run on the server so they can do whatever you need them to. Nice DX improvement there!

Your entire app

Remix giving you the power of the server means that it can actually handle your entire app if you need it to. Not everyone wants to do things this way, but because you've got a backend that can talk directly to databases and third party services, you can make your app structure look more like this:

Similar to the diagrams before with the addition of a "Full Stack" row that shows Remix spanning over the entire client, network chasm, and server

The cool thing is, you get all the benefits of a fully managed network chasm by using Remix whether you go with 100% Remix or not, so if you're happy with your existing backend you can certainly stick with that.

Conclusion

React's tagline is:

A JavaScript library for building user interfaces

And it does a terrific job at that. React has never promised "network chasm management," but every web application needs it. With Remix managing that network chasm, we finally have a yang to React's yin. With a great rendering library and a super network chasm manager, you can build better, faster web applications with fewer bugs, simpler code, and more fun.

On a personal note, this is what made me fall in love with building web apps with Remix. The website you're reading this on today is the result of a rewrite to Remix. I had no idea when I started what cool things it would become. Remix enabled all of that because when I was finished with the basic features I realized I had time and capability to do so much more (read more about my site rewrite here). Remix made me feel like I could say "yes" to the fun ideas I had and that was really refreshing.

I hope this helps you in your pursuit of building better websites. Stay cool 😎