Hacker News new | ask | show | jobs
by puildupO 168 days ago
Haha yeah you are right, that is exactly the thing I was tripping over, I had React state just babysitting the DOM for no real product win. And your approach is a cool mental flip ""Stop syncing, just read what is already true"" that fits perfectly with the whole HTML first then enhance idea.

So, I have two quick questions though, because this is where I always get nervous: - First, where do you draw the line between DOM state that is fine to trust and app state that should still live in data, like validation errors, derived values, server driven defaults, stuff that needs to be consistent across SSR and client. - Second, how does the MutationObserver part behave when things get busy. If a page has lots of inputs or updates, does it stay cheap. Do you scope it per form or per component, or is it one observer with filtering.

Either way the 2KB no deps thing is a flex, dropping a link is fair, people can decide if they want that model. I am going to skim the repo.

1 comments

Great questions, these are exactly where the mental model matters most.

Where to draw the line? The answer is "further than you'd think." Validation errors? data-error attributes or aria-invalid on the input. Derived values? Compute them from DOM on demand rather than caching. Server-driven defaults? Server renders them INTO the DOM, then DOM is truth.

The key rule of thumb: if it affects what the user sees, it belongs in the DOM. If you're putting state in JS just to render it back to the DOM, you've created a sync problem. If it's data persistance or state that only code cares about... back-end, pure function, using some efficient memory structure.

SSR consistency is actually easier this way. Server renders HTML. Client reads it. No hydration mismatch because there's nothing to reconcile.

MutationObserver performance? Scoped per component, not global. Use subtree: false when you can, attributeFilter to watch only specific attributes. The browser batches mutations automatically (delivered in microtask), so rapid changes don't mean rapid callbacks.

In practice it's cheaper than React's virtual DOM diffing for most UI. You're not diff-comparing object trees, you're getting notified exactly what changed.

The DATAOS book (https://dataos.software/book) goes deeper on the architecture if you want the full philosophy.

Thanks, that explanation is clear. Two things I am still trying to picture in practice.

- For ""derived values from DOM on demand"", what do you do when the derived value is expensive or used in multiple places. Do you just accept recomputing, or do you have a pattern to keep it from turning into lots of repeated DOM reads. -And for bigger interactions like table row selection, keyboard navigation, drag and drop, does your approach still model that as DOM attributes and queries, or do you keep a small in memory store for that kind of state.

The MutationObserver tips are useful too, scoping and attributeFilter feels like the difference between this being neat and this being a footgun. I will take a look at the repo and the book. Thanks