Auto Refresh
Moving to a new place can be exciting, but it also brings a tedious task — updating your address with the postal office, your bank, your insurance provider, and any other service you use that requires your physical address.
This process can be compared to the often-overlooked programming task of manually refreshing queries after actions are performed. One example is that a to-do app might need to update the task list after the user marks a task as complete on a details pane. While refreshing a query may not be as exciting as moving to a new place, it’s a lot more frequent, and can result in a stale app if not done correctly.
This is how it would looks like in the codebase for a task list app:
async function completeTask(task) {
await updateTask(task.id, { complete: true })
// Manually refresh the list
await refreshTaskList()
}
Last week’s essay was all about this problem. This pattern is bug prone because it relies on the developers to remember to refresh after each action, not just when writing new features, but also when changes happen. Today we’ll go over some ideas on how to remove the need for a manual refresh, and ensure our data is eventually up to date after every action.
While the tech stack will influence your architecture, one thing is true regardless: Somewhere in your codebase you need to encode the causal relationship between an action and the query that needs to be updated.
If you have a hosted API, that means the knowledge of which query needs to be updated lies on your backend, and unless you want to duplicate that logic on the frontend, you need to send that information from your server to your client.
If all you care about is updating your lists after an API request, you can add a header or a response property to inform your client which queries to return. With some extra effort, you can use websockets or long-polling to notify your client even if they didn’t send any requests, enabling features like realtime collaboration and multi-device sync, but we’ll dive deeper into those topics in a future post, so let’s just assume your API response has a X-Refresh-Queries
header.
You can listen to those triggers in a few different ways:
Create a wrapper: Whether you wrap
fetch
with afetchAPI
function, or you create a full ORM with all your types, these solutions centralize common logic, like handling errors or triggering a refresh. All we have to do is call the appropriate refresh function after reading the response headers.Web worker that intercepts requests: While this can add a lot more complexity to your app, it enables you to just use the usual
fetch
call, and it will intercept them, read the response headers, and send the correct event.Apollo Afterware: If you use GraphQL and Apollo, you can use an afterware to get response headers, and trigger any required refreshes.
Be careful to not just move the manual refresh from client to server! The purpose of having this logic on the server, is because it will know which database tables have been updated, and therefore which queries need to be refreshed. If your API is still manually creating a list of which queries need to be updated after each DB operation, then you just moved your problem from your frontend to backend.
These refreshes can also be triggered directly from the client, especially if your app has a fairly transparent database or data model. Tools like Prisma, Supabase and Postgraphile provide a quite predictable API based on the structure of your data, so you can add middlewares or wrapper functions that will trigger a refresh on any active queries for a table once operations on that table are executed.
While these solutions ensure the right queries will run after each request, the client still has to wait for 2 requests (the action, and the refresh) before updating the UI. We’ll explore this problem deeper in future posts, so don’t forget to subscribe!
Status
Nov 21 to 27
📰 Selfeed
A productivity app using the same feed gamification strategies from social media apps.
I’m experimenting with habit tracking, and I created a shiny indicator to motivate achieving a personal record when working out. And it really messed up with my head! I pushed myself so hard this week just to make sure I’d get one of those medals again!
👗 Fashion Fusion
AI-Generated Outfits
This week, instead of using Dall-e 2 to generate outfits, we tested DreamBooth with Stable Diffusion, in order to get different kinds of photos. Here are the 3 ok images out of the 22 we generated:
Projects by the Numbers
▶️ VSCode Run Function
Downloads: 86
(previous: 88)
📺 Screen Box
WAU: 11
(previous: 14)
📰 Selfeed
WAU: 2
(previous: 2)