Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
It's time for a data-first front end revolution (kea.js.org)
93 points by feross on May 18, 2021 | hide | past | favorite | 64 comments


Honestly, why not just use Clojurescript if that's where the inspiration came from? With Clojurescript/re-frame you don't have to think about which of the myriad useX inventions apply to your app. Every couple of years React seems to be throwing-out more clutter (hooks, forms) just to get a bit closer to what Clojurescript + re-frame has had for years.


Strong plus one. Not to mention that I often see highly experienced frontend devs writing components that re-render itself on every change, just because it's so easy to make the mistake of unnecessary re-rendering on modern React.

Developing with re-frame means you re-render only when data actually changes, with almost zero chance of making accidental re-renders, and no need to spend mental energy on "should I wrap this with useCallback or useEffect?".


Something that comes for free with Redux and its abstractions like Kea (the approach promoted in the linked blog post) is that you mostly avoid the problem of needless re-renders.

Each `useSelector` call (and `useValues` call that uses it) triggers a re-render only when the value changed. So unless you have something forcefully re-rendering the root node, only the few relevant sub-sections of the page will re-render.

It's not perfect nested-sub-object level precision, but in practice works well enough.


Yet more useX to keep in your head. I don't get it with React.


In the approach described in the blog post, you only need two use*: `useValues` and `useAction` to pull in values and actions from the data layer. Nothing else. No local state with `useState`, no `useEffect` or `useRef` or anything else for interacting with your data. So in effect React == two hooks and JSX.


I was thinking more generally where idiomatic React makes use of the whole panoply of use* variants. React is unusable for me because of this. useForm alone has exploded recently into a proliferation of sub-variants then when you add useController into the mix it's game over.


It seems like you're talking about the APIs for a specific library (React Hook Form) rather than React in general.

Overall, hooks allow libraries to package custom behavior. The `useSelector` hook mentioned above is a React-Redux-specific API that manages subscribing to the store and re-rendering the component when the requested extracted state value changes. So, the "proliferation" you're talking about here is simply libraries and individuals building their own specific logic on top of React's primitives, in the same way that users build specific components on top of React's component primitives.


Isn't React Hook Form ( https://react-hook-form.com/) from the React team?


No. The React team doesn't work on _any_ official libraries except React itself.

Brian Vaughn did create `react-virtualized` and `react-window`, but he maintains those separately from his status as a React team member.

React Hook Form is from a community member named Bill-something, I think.

Out of curiosity, what gave you the impression that RHF might be from the actual React team?


It’s definitely easier to swap all of them for a simple useElm.


When some organization gets serious about providing complete ClojureScript education and tutorials, especially covering the setup/config challenges... and then keeps those current so the examples always work, then this could be a reality.

But as long as a newbie has to piece together their own solution from many optional libraries and build systems, the initial time investment will dissuade people from taking the plunge. Of course, an established Clojure shop has already gotten over this hump and can easily onboard and bring new devs up to speed.

If the Clojure world never realizes they need to get serious about providing quality education, then Clojure will decline in use relative to other options. It's a shame.


Because you will reduce the number of potential candidates for hiring by one or two orders of magnitude, even if it might be a technically justified choice.


This is always touted as a reason but honestly I always spend time teaching the hired new frameworks, JS knowledge, ecosystem knowledge, etc. The world already operates on multiple languages and JS is already an exhausting confusing ecosystem. There’s no reason not to use something because it’s in a different language.


I've seen developers being productive with our frontend in React in a day.

Additionally, this is not only about new staff. Your current team has to learn the new tech as well and many can't or don't want to spend much free time on things like this.


I’d be willing to bet that Devs could be productive with Clojurescript in a day.


But you still started from scratch. With productive I meant that they can jump right in with their existing knowledge. If you learn some new tech, you might be able to solve a simple task after a short period of time. But you will still have to learn how to best handle basic problems for weeks.


Interesting how you immediately went to free time offerings for some business decision that would benefit the company.


I'd also not expect it from anyone. But that's typically how new tech gets introduced. Some lead developer tries out something new in their free time and introduces it into a new product. Others don't spend free time on it, so the company pays for teaching everyone on the team. The tech needs to have a real advantage to justify that overhead.


Only if your company doesn't believe in training.


I feel the same way, but it could be a really big commitment to choose ClojureScript for a lot of projects. I have my own shop and haven't had an opportunity where I felt comfortable suggesting it, even though we have a few devs that would love to use it.


ClojureScript is great and it'd be my first choice if performance doesn't matter. For me the drawbacks are that bundlesizes tend to be bigger than using js. Profiling is much harder due to the output from the google closure compiler is somewhat opaque. Reasoning about memory allocation and leaks can be quite difficult even in a complex js app, having persistent data structures makes this an order of magnitude more difficult.


I've been developing small scale react applications since 2015. Application state has seldom been a problem for me.

Initially classes were a problem as they made unit testing harder. I'm happy react moved towards functional logic.

Integration tests were hard because there was no good one-stop-shop framework. I now use cypress and it's OK.

Tooling was hard as there was a bazillion options and nothing stood out. I now use esbuild. It's pretty good.

I once made the mistake to use redux to fix a problem I didn't have, namely handling application state. Then I tried MobX.

These days, I mostly use component state and a REST api. For reusable components, I create an npm lib. Whatever.


I suspect this is right.

I've been with the JS world long enough that I've seen a lot of the major iterations – each solving the problems of the last.

- Jquery solved the browser inconsistencies and limitations of vanilla JS

- Backbone added MVC structure to large, disorganized soups of Jquery

- Angular + Ember gave you a more full-featured MVC so you didn't have to rebuild common logic on top of every backbone app.

- React switched to a component-oriented architecture as we realized that MVC wasn't a great fit for frontend.

I think the next big problem that will be solved by the next big JS change is that organizing and interacting with your data layer is a pain. Redux is complex* and is a ton of overhead for a lot of use cases. Tools like React-Query make handling one kind of global state easy, but do so by mixing it up with the view layer.

A strong contender for the next dominant frontend approach (whether that's a single framework, a data layer that works with react, or a new set of tools) will be one that really tackles the data layer well.

* Redux actually really simple at its core, but it's such an incredible ton of boilerplate that everyone inevitably builds their own complex and bespoke tools for dealing with it.


Note that we created our official Redux Toolkit package [0] specifically to solve the "boilerplate" concerns. It includes utilities to simplify several common Redux use cases, including store setup, defining reducers, immutable update logic, and even creating entire "slices" of state at once. The "Modern Redux with Redux Toolkit" docs page [1] shows how to migrate from hand-written Redux logic to use RTK's APIs.

We've had a ton of very positive feedback from folks who love using RTK, and even from folks who didn't like Redux before.

Also, we're currently finalizing a new "RTK Query" API for Redux Toolkit [2] that provides a purpose-built data fetching and caching abstraction layer, which basically eliminates having to write any of your own code to fetch data. That's available now in the RTK 1.6 alphas [3], and we hope to publish that live shortly.

[0] https://redux-toolkit.js.org

[1] https://redux.js.org/tutorials/fundamentals/part-8-modern-re...

[2] https://deploy-preview-1016--redux-starter-kit-docs.netlify....

[3] https://github.com/reduxjs/redux-toolkit/releases/tag/v1.6.0...


> one that really tackles the data layer well

I believe this should be rxjs. It's composable: have a stream or streams create new derived streams easily. It's lazy: you can describe what to do with data before it's available. Handling state for the multi step or async operations (loading state, cancelling requests, retrying operations) is a breeze. "Wire" your application with rxjs and you'll never have trouble modelling state with it. Typescript-friendly. It allows be both sync access to the value (BehaviourSubject) and async (Observable). I work with it closely last year and there was no situation I could not model with rxjs.

But people will stick to whatever is hyped by well-known-internet-company. Marketing wins, not quality.


> Tools like React-Query make handling one kind of global state easy, *but do so by mixing it up with the view layer.*

This is where I think `react-query` fits a very specific niche. I see a lot of new projects reaching for it and while I think for simple applications it can work fine, I have a serious problem with it for large applications: it's baked into react. React is a view layer that is slowly consuming the world and while I don't think react is going anywhere, people are starting to feel the burden of a black box system.

As someone who's primary job has been building large scale web applications for the past 7 years and has weclomed the chaotic nature of the FE ecosystem, I'm starting to feel a little less optimistic about react's future.

That's why the allure of something like redux is so strong for some of us. Redux is not that complicated and the boilerplate has mostly been reduced to a few lines of code.

React is continuing to grow in complexity with hooks, suspense, async rendering, and now server components. I think for personal projects I'm probably going to reach for something else like Svelte.


Of everything I've used over the last 20 years, nothing has felt more simple than re-frame[0].

It's built on React but it's ClojureScript, so it probably wouldn't be an easy option where already invested in another ecosystem, but it's a real pleasure to work with if you can, especially if you buy into the tooling for your editor and browser.

[0] https://day8.github.io/re-frame/re-frame/


  It means going from:
  
  Frontend > React > [state management library of choice]
   
  to
  
  Frontend > Data Layer > View Layer (React)
This is MVC, no? That's basically the diagram for MVC on the Wikipedia page.

I suppose giving it a "-first" (god I hate this trend) moniker spiffs it up a bit. We could also name it "modern MVC" for ultimate internet points.

I'd also read this article (not mine):

https://chriskiehl.com/article/react-as-an-implementation-de...

Pay attention to the caveats. Specifically:

> The complex pieces usually warrant it, the simple ones usually do not. There's nothing original or revolutionary in these ideas, they're often just forgotten.

And that's probably why we do React with ad hoc Redux today. It's the path of least resistance. Why think about boring business rules and how to model them with lots of tiresome boilerplate when you can just throw up a prototype in React. You could probably fit a good argument of why so many people reach for NoSQL over SQL in there too.

Ultimately, all code starts simple. So you're screwed from the start. Only later do realize your code is a mess and your lack of modeling is causing chaos everywhere, from one-off TypeScript interfaces everywhere to lots and lots of null checking.


React and MVC would be a pretty good mix I reckon. I did some early React projects with Backbone.js instead of redux and it worked pretty well.


State management in Frontend really is a solved problem if you know what you’re doing.

Use a tool like swr, react-query, or Apollo-client.

I personally use graphql and my front end client manages most of the global state automatically.

Change a field, and it updates in other components.

Simple local state for modal transitions and other routine logic… and that’s all I need.

Every week there’s a new article bashing front end complexity with redux as the scape goat.


Agreed that if your frontend is mostly GraphQL, and your data flow well taken care of, you shouldn't see a need for a separate state management solution.

However sometimes you have to work with various APIs and filter/display/modify/update/delete/change/patch various parts of the responses you receive. That's the environment where solutions like Kea (mentioned in the blog post) come into their own.


You summed it up perfectly, react-query aims to literally solve this exact problem.

It does it quite well I might add.

React, Mobx etc are all reactive frameworks exactly for this reason. Given a set of data render x, update the render every time the data changes.


Flux and MobX are good if you don't want to fetch the server on every action or if you have a lot of cross references inside the data layer.


> By following a few principles of immutability and purity, React frontends were generally better written, stabler and easier to debug, compared to contemporary alternatives such as Ember or Angular.

I have the exact opposite experience. Our large Ember application is a lot more maintainable, and requires a lot less boilerplate code to get things done, than this React Native app that I'm working on.


I concur.

Angular's framework contains all the baked in patterns that is friendly for a large enterprise scale application.

DI, Angular Modules, opinionated patterns.

More boiler plate yes, but small, one-time cost to pay, for a scalable pattern that the entire community subscribes to


completely agree. every React app that I have ran across that used 'best practices' for React development has been an unmaintainable dumpster fire.


FTA:

"It means going from:

    Frontend > React > [state management library of choice]
to

    Frontend > Data Layer > View Layer (React)
"

I'm not really sure what "Frontend" means here, but I'm pretty sure this is how I was using React + Redux, back when I was developing in that ecosystem a ton. I certainly wouldn't diagram it as the first example.

The hard part with doing this "purely" is that it'll murder performance for text inputs and animations. All this developer-centered convenience comes at a performance & resource-use cost to the user, it's just most-obvious when you're dealing with forms and animations.


Having also been in that area, I almost never put forms or animation state into the redux store. Sure, you lose a certain amount of time-travel goodness, but it made for a much saner development experience (especially where performance was concerned).


Yes, we specifically recommend that most "form state" should _not_ go directly into Redux:

- https://redux.js.org/style-guide/style-guide#avoid-putting-f...

- https://redux.js.org/faq/organizing-state#should-i-put-form-...

In other words: it's fine to take data that's in the Redux store, use that to initialize a React form, do the form updates in local state, and then dispatch an action containing the final results when the form is complete. But, there's almost never a good reason to dispatch a Redux action on every keystroke. You don't need to track that level of granularity in the Redux DevTools, other components in the app are unlikely to need to see those individual updates, and it's a waste of update and subscription handling.


If only my PMs had cared...

I previously worked on a monstrosity where the input state was owned by the backend via huge incomprehensible metadata updates. Every keystroke had to be submitted (and thus actions fired) because a field update could invalidate other fields on the grid and the user could feel the latency (~400ms roundtrip?) between each keystroke. The backend team was sure they had discovered some magic sauce and I noped out of there before my next bonus


By the way, about that "dispatch an action containing the final results when the form is complete" — what is the Correct Way™ to do this, if there may be several instances of the form? They should produce different actions so that different pieces of state would be updated.


"It Depends"? :)

Typically if you've got a single React component type that is supposed to be reused in multiple places with differing behavior, the right answer is "pass in something as a prop". In this case, that could be a callback function that dispatches the correct action, so the form component can just do `props.onFormCompleted(data)`, and the differing usage sites can pass in different callbacks that dispatch different actions.


Yeah, you basically can't do that without wrecking performance, which is why I think attempts at more "functional purity" (which, LOL, React has now entirely abandoned anyway, see: hooks) and "single-source-of-truth" than what's currently the norm in the React world (or anywhere else in FE web dev) are misguided.


I still prefer a global store and keeping functions as pure as possible. I just make a distinction between application state and ephemeral (i.e. local state such as drag / drop tracking, forms, etc).

There are a number of advantages to centralizing your event handling pipeline and using middleware functions to perform many of the more important side effect producing behaviors (i.e. analytics events, etc.).

YMMV though, and I now that I am working on an app that makes extensive use of hooks and useContext, I cant say that the world has ended (even if it is quite a bit more confusing).


“Svelte has solved all of these problems. State is trivial, DX is unprecedented, reactivity is default, learning curve is non-existent (it’s just better js and html but can be written in dated verbose vanilla crap ) community is thriving, ecosystem is unmatched (entire js ecosystem free without wrapper, no “does this library support X framework” nonsense), performance is unmatched (and can essentially be ignore because it optimized itself at compile time).

I feel like I’m watching an army of people run around scrambling to find and produce food with pool noodles, meanwhile it’s been years since the all-you-can-eat free buffet was opened to the public.

I can’t wait until more people snap out of it and adopt Svelte, for the sake of the industry and all internet users. The next stage of evolution is already here, join us already!”

-My thoughts everyday


Only vaguely on topic: what's the current state of the art around offline-first apps with data syncing? Particularly, something that works like PouchDB, with local databases for web and mobile clients that sync to a centralized source of truth.


The industry is definitely dropping the ball on offline. To give us credit, legal/privacy issues don't make it easy.


It seems like the article is talking about Elm.


Basically the rule in front-end land is to keep poorly reinventing stuff that Elm has done elegantly for years without much fanfare, all the while pretending that Elm doesn’t exist.


Yeah, now that you mention it, yeah. Elm is the natural progression down the functional programming rabbit hole for the frontend. Either that, or ReasonML, which I haven't seen much news for recently.


They renamed Reason to Rescript, FYI. (I don’t actively follow Reason or ReasonML, but the rebranding caught me by surprise).


Might explain why Reason seemed to have fallen off the face of the earth for me. I wasn't really keeping heavy tabs on it, but was more waiting for its tooling to be more mature.

Will have to check it out again, I suppose.


Data is always first with redux + redux-saga. I haven't used reframe but have read the documentation a number of times. redux-saga seems like a pretty great alternative that is very popular in the react/redux world.


I remember this when it was XML -> XSL -> HTML.


This boils down to the original confusion around hooks. Putting a sequence of useData / useState hooks inside a View component is just as "data-first" as wrapping a View component in HOCs for the api and app state.

Ultimately it comes down to how you structure your components.


Application state is a trivial problem to solve. Even better is that if you figure it out once you can carry the experience forward to any other project.

The only reason people perceive this to be a real concern is because they have never done it without a framework.

https://github.com/prettydiff/wisdom/blob/master/state_manag...


> Application state is a trivial problem to solve.

This is very interesting. Can you show example which you believe trivially solves state?


Nevermind. I saw the code by the link.


Isn't this the normal way of React with Redux? It's how I've seen it done for years.


If you design a set of views to act as a part of a particular domain, then this will lead to API's for that domain and that functionality.

The data you view and the data you store is just communications and absolutely should be last.


https://xkcd.com/927/

seems relevant.

On a more on-topic note -- this data-oriented structure seemed to be at the core of the goals of Vue 3, to the point where you don't even need to use their Flux implementation, Vuex, anymore for 100% vue3 projects.


Higher Order Components work well for what's described. But they were thrown out of the window.

And yeah, all the rage is hooks which also will soon be thrown out the window.


The only thing stopping you from writing higher ordered components is you. If you are not maybe you found an alternative you prefer.


No, it’s the job market that dictates what people write.

It’s frustrating that people I care about who are going for entry-level positions will fail an interview because they didn’t demonstrate usage of the interviewer’s pet favourite reinvention of some basic UI development concept.

Oh! You used Redux and you didn’t use hooks! Sorry, no job for you.




Consider applying for YC's Winter 2026 batch! Applications are open till Nov 10

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: