I've been working on a React side project for a few months now and looking at my company's apps plus posts like this I think people just miss the point. Stuff like this:
>Things get more complicated when you start using React Context and start signalling updates in a parent component. The render cascades. Maybe one component fetches some data, some component remounts, and you run your state update again, delayed by a few seconds.
This is just doing it wrong. State should change in response to user inputs. Ultimately, React is f(newState) => UI. If that function isn't pure you're gonna have a bad time. It's hard to blame anyone though. The docs suck and most of the tutorials you find get it wrong one way or another.
That said, there's kind of a reason why functional programming isn't more popular. It can be hard to grok and there can be a significant performance overhead. There's also a reason why this sort of implicit programming isn't as popular as imperative style. It's hard to predict what the implicit behavior is and footguns abound.
I get so lost in these conversations, because I've been the lead on a relatively complex React app for literally years now and none of any of this has mattered or come up in any way whatsoever. Our app is plenty fast/responsive, maintenance hasn't been perfect but it's been manageable, same with new features... The learning curve around context was a bit steep but we get it now and haven't had any issues since.
It's like you're speaking a different language to me, and I find that so weird considering we're using the exact same framework. How am I not having any of these issues?
I'm honestly at the point where I wonder if y'all are making things harder on yourself somehow, because I could see how getting obsessed with counting every single re-render and trying to overoptimize would result in the stuff you're saying while not actually impacting perf in a meaningful way.
I've been in the same boat with these discussions.
When I do encounter a component with countless re-renders as described, it is usually painfully obvious what causes them and easy enough to fix.
I think we're going too far if we're expecting React, or any framework, to be fool-proof to the point that we can just throw "whatever" we want at them and expect it to have peak performance.
Depends on what kind of so your building. For a while, a lot of the form libraries out there triggered huge numbers of rerenders and caused perf issues. That's still a problem, though some of it has gotten better uncontrolled components.
Timing-based UIs are (such as a sequence of triggered animations) can get really messy really fast. I've seen some really messy bugs in a app that had visuals and audio tied to different timers and user inputs in the app. We eventually moved all time-based animations to observables, which helped some
Sure, but then you're managing state and re-renders yourself. Kinda defeats the purpose of using the framework, right? The useRef() approach to fixing performance is the main reason why I think Signals are popping off. Users of frameworks like Vue and Svelte have felt this way for a long time.
I've worked on a form + animations based site ~2 years ago. Forms via higher-order functions, it was a full-stack NextJS thing. Without TS.
I had to eventually claw my eyes out and that solved part of my problems, at least I did not see the boilerplate and the ugliness.
Then soon after that we worked on a similar thing (form + draggable carousel with snap to grid animation) in Angular with Material.
And my conclusion is that whichever framework you pick, whatever libraries you end up using, you must have a strategy to allocate your time and maintenance budget, and many many many times the sane compromise is to write something in raw JS and encapsulate that in whatever the framework gives you, and move on. Don't try to solve it within the framework, because it's just not worth it.
Forms were annoying but `react-hook-forms` eliminated any random issues we had, and now forms are fine. Again, context saves the day here by letting me grab the form context within nested components to keep everything humming.
I don't know if we have any "timing" based components, though we manage global state using Apollo Client and again, haven't really had any issues with that.
In my experience redux-toolkit + redux-saga for async stuff usually work really well. In case of performance problems one can go with profiling + targeted optimisations (e.g. a separate store, some locally managed state).
Glad to hear RTK is working well for you! FWIW, we actually specifically recommend _against_ using sagas in almost all cases. Instead, we recommend using our RTK Query API for data fetching and caching, and the RTK "listener" middleware for reactive logic:
Thanks, I wasn't aware RTK now has a saga-like "listener" feature - will look into it!
What I like about sagas are their simplicity & power (once one understands how generators & effects work), plus the eventChannel feature which lets one integrate with non-redux events. Good TypeScript support is a problem though, and I've had to resort to typed-redux-saga :/
Yeah, we specifically designed the listener middleware to do ~90% of what you could do in sagas, but with a smaller bundle size, simpler API, and better TS support:
Event channels was something we intentionally _didn't_ try to replicate per se, and tbh I've never tried to use those myself. (But, I _suspect_ that you might be able to do something similar with listeners even though we don't have a specific replacement built into the listener middleware, and if you do I'd love to see an example in action!)
If you get a chance to try out listeners in your project, I'd definitely appreciate feedback on how well they work out for you - whether they solve your current saga use cases, what cases they _don't_ handle, anything we can do to improve the listener API, etc.
I had to rescue a redux-saga project that went badly off the rails. It was one of the most inscrutable and difficult to debug codebases I've ever had to work with. Forget completely about ever having a usable stack trace.
This is why people use redux, keep state in a store and just do v=f(state).
Your app is the store, not the DOM.
It really makes things much simpler. The trick is to keep all the state in the store, including when things are loading, when some user interaction is happening but not yet complete, etc.
From your comment, it seems like there may be some problem if the user is interacting somehow, let's say in the middle of doing a drag and drop, and some data update comes in from a websocket, right? Well, if that's going to cause a problem for your render it's because apparently your data-updated function h needs to know if the user is doing a drag and drop. That should get put in the state when the user starts the interaction, and now h can know about it and react correctly.
Yes, it's more complicated than just have some component render based on the data you receive, but that's because it turned out that your app was more complex than you thought, it has more states you need to care about.
There's no magic wand, but this stuff works, just adds some boilerplate code but I don't mind.
>> I've been working on a React side project for a few months now and looking at my company's apps plus posts like this I think people just miss the point.
The clue is in if everyone is missing the point but you, may be start with more introspection. :)
I will give an example of a side project I am working on. The homepage has two sub components, one when the user is logged in, one when the user is logged out.
Now, when the user logs in, the state of the homepage parent component needs to change, the state of the nav bar needs to change etc.
Your problem is in assuming newState is completely described locally which isn't always the case.
GP's post reads like a definitive example of Dunning Kruger. These are large-scope issues that the article highlights likely won't be apparent in smaller efforts that could be referred to as a "side project".
You are both right. React components should render based on state that is managed by React, such that the
rendered output changes only if the state changes.
The complicated bit is the handling of events and changing the state. Hence why you get Redux for state but there is no “Redux for views”
React very heavily pushes "component lifecycle" events, since it was class based up until now with hooks. That is, changing the state in the view function itself.
It's not wrong, it gives you one kind of separation of concerns: components. But "the view is a function of state" is completely misleading IMO.
The linked article doesn’t convince me, instead it shows a misunderstanding of react and hooks.
> But then they added hooks and useState and useEffect and so on, which made the functions impure. The problem with hooks is that they “hook into” React state and lifecycle features, which means it is modifying global state.
React components don’t update the dom every time they run, they update the fiber tree / virtual DOM.
Only in the commit phase is the DOM updated and side-effects are run.
My rough understanding is that:
Hooks, excepting useEffect, all run in the render phase.
UseState hooks store data in the component in the fiber tree, and capture a sequential list of updates when you call setState.
Algebraic effects can seem a bit odd at first, but it’s really like a generalised try/catch. Instead of storing state in the function itself, you reach out up the stack to the component and store it there. And every hook you call from your hook stores it there too.
It’s why call order is important, because it’s how they know which is which.
You don’t modify any global state though.
The actual component function needs to be able to be called multiple times in the render phase (which just updates the vdom), and must have the same output each time, if the inputs/props are the same.
Every now and then, the tender phase can be interrupted to run the commit phase, which synchronously brakes a snapshot of the vdom and applies all the needed updates to the outside world.
I would absolutely say components and hooks are functional, with algebraic effects. And that the resulting data struct from those components, is what’s used to produce side effects.
Even useEffect, is a description of a side effect to run, it doesn’t run in your hook, it runs on commit with all the other side effects.
There’s a ton of optimisations under the hood but that’s roughly my understanding of how it works.
> ...and capture a sequential list of updates when you call setState.
In functional programming, functions are not allowed to do that. The only thing a function is allowed to do is return a value.
> ...you reach out up the stack to the component and store it there.
FP functions are not allowed to do that. In FP functions can only rely on the parameters passed to it (it cannot refer to anything outside) and it should not do anything beyond return a value.
> It’s why call order is important, because it’s how they know which is which
In FP, functions can be called in any order (unless one function needs the return value of another), and the final result is not affected by the order.
> You don’t modify any global state though.
If you have state it is not FP, whether it is global or not.
I find it's best (if side effects and state mutation make you nervous) to think of hooks as essentially part of the function signature of a react component, both on the parameter side, as well as on the return side. They are not written as such, because of syntactic limitations of JavaScript, but essentially a react component that starts off like this:
In this version, those hook functions are side-effect free, pure functions that our caller provides us with, closed over the previous stored state of our component in the tree; and when we return the results along with our rendered output, our caller has the new state of our component together with our desired DOM.
Instead of forcing us to write all that extra code, route those extra variables, and figure out the metadata mechanism whereby the caller of the render method figures out what hook functions to supply, the rules of hooks let you use JavaScript's imperative, procedural syntax to call hooks which are implemented using ugly side-effecting impure techniques, but in a way that pulls off something semantically identical to this pure functional flow.
Don't call this functional programming. If you call setCount() then this is not functional because your function is doing something besides returning a value. In fact, it is setting state, which is against FP principles.
Most of the ideas at play here come from the functional programming world, which is why it’s often viewed from that lense.
React builds on functional reactive programming, something the FP world is known for[0]. I’m not saying it’s pure FP in the dogmatic sense, I just wanted to point out it’s closer to FP than the other paradigms.
Without the ability to interact with the outside world (side-effects), FP is not of much practical use. Not to say it’s bad or shouldn’t exist, just we need to add to it a bit to make it useful.
Why would we do that? Because the underlying ideas and principles provide a great foundation. Building on that to get FRP and algebraic effects, monads and so on, is very different to starting from OOP and brining FP ideas over.
React hooks are an interesting and tricky thing to put in a box, because they’re almost monads, almost thunks, almost algebraic effects. The interplay with fibers and components makes them hard to pin down, but they are much closer to functional than any other paradigm.
The web is (was) a pretty good example of something akin to FP: REST means all state is transferred with the response and then the whole thing is rendered in the browser. And then there is HTTP, so if you want a new page, you simple call another URL (like a function call). OK this is glossing over some parts like that cookies are also send, but they are additional optional arguments of that request (function call). That's what the mean (or meant, since the term is now muddied), when they say the connection is stateless.
What we have with badly written React apps now (90% approx.) is a UI, that is not at all behaving like a typical website and very far from being like FP. We often cannot simply go back with the back button and expect to see the same page rendered. I mean we can, but the websites will fart in our face, if we do. We do not get the ability to simple send a link to someone and have them see the exact same page. It is a huge departure from anything FP.
Furthermore from the dev perspective components feel more mainstream OOP than FP, since they store internal state and update it, which indirectly causes things I described above.
Not sure where people see the FP. Not sure they really have done any FP language before or tried in projects to strictly adhere to FP principles, because that looks a lot differently than React components and mixing state, layout and styling in JSX/TSX.
> React hooks are an interesting and tricky thing to put in a box, because they’re almost monads, almost thunks, almost algebraic effects. The interplay with fibers and components makes them hard to pin down, but they are much closer to functional than any other paradigm.
They're almost classes (/objects). The implementation is what it'd look like if you wanted to make a weird half-assed OO... thing. Property and method declarations, getting attached (ultimately) to an object. But it's FIFO access/calling, rather than using named properties and methods w/ a lookup step. And the declaration syntax is bizarre and hard to read. And they're slower than regular JS OO (because they add an extra layer of JS on top of it).
Okay. But is it against FP principles to write software that runs in web browsers then?
Because web browsers exist, and they work in a nonfunctional way.
So to interact with one we need to do a little bit of imperative code.
And then react lets us figure out what to do when the web browser responds to that imperative code by letting us run a largely functional program.
Which is pretty neat considering we’re doing so in JavaScript.
The thing that we’re after here is not a badge that we can slap on our code saying ‘certified 100% functional’. We are trying to write code using patterns that help us reason about and structure what we want the computer to do, avoid bugs, and ship software.
If react managed to squeeze a surprisingly functional pattern into a JavaScript library to that end, can’t we just applaud the audacity and enjoy using it, without nitpicking that they didn’t actually reimplement the lambda calculus?
Why is it necessary to use FP to write software that runs in web browsers? To be sure, FP has benefits (such as, it is much more straightforward to reason about FP code), but those benefits are not applicable in React. So why pretend it is FP?
Web browsers are agnostic to the programming paradigms employed to code websites in. We might need to bend JS a lot to get FP though. JS has some quite procedural roots/basics. For example the timer API (setTimeout and so on).
I don't know react details but set<X> are not effecting directly, it's just another iteration from prev -> next state (with the values given in set<X> hooks) which is functional.
> In functional programming, functions are not allowed to do that. The only thing a function is allowed to do is return a value.
Oh, yes, they are allowed to do that. You capture the effects into a list, and return the tuple of list and return value. If you feel like it, you wrap that into a monad to pretend you are only "returning" a single thing.
> In FP functions can only rely on the parameters passed to it (it cannot refer to anything outside) and it should not do anything beyond return a value.
You mean explicit parameters (props) and implicit parameters (context), right? I thing you forgot the latter. Implicit parameters have existed for quite a bit, for example in the reader monad.
> In FP, functions can be called in any order (unless one function needs the return value of another), and the final result is not affected by the order.
Yup, except if you write a bunch of functions and store them in a list with the intention of applying the result of the first entry of the list against the first entry of the list. Now, if you construct the list of functions as effects (by hiding them behind a monad) you find out that you need to call the effects in the same order as to construct the list of effects in the same order. This doesn't contradict FP, it contradicts your mental model of how React is supposed to work.
> If you have state it is not FP, whether it is global or not.
The state resides in the runtime executor, exactly like Haskell's IO monad. Again, this contradicts your mental model, not React or FP.
Wow, I've never seen a reply that so thoroughly fails to address any of the points it's trying to reply to.
When you reply to "in FP, functions cannot do that (change state anywhere)", you say "you are allowed to do that: capture the effects into a list, return the tuple of list and return value" without realizing you're saying exactly the same thing?! The distinction between "return value" and "return value plus some other thing" does not exist. What matters is that the function's only observable modification is in what it returns, be it one value of many. This is basic FP.
You return a tuple, which first element is the value the function would return (I/E "return jsx stuff") and the second value is a list of operations (effects) you intend to perform I/E "I intend to change this variable to value X", "I intend to run this external function when these values change".
The function's only observable behavior is that it returns a tuple with JSX and some effect descriptors.
No, this is not basic FP. This is somewhat advanced FP.
I think you may be missing the forest for the trees. The point of FP is that you can glance at a function and say 'this is obviously correct' without having to work out the state and context of every call.
None of that is true in React hooks. The negative sentiment towards hooks that you see here is because it is weird and complicated. Want to see how much simpler code can get when you code without React or any such fat frameworks?
You just need to know JavaScript, HTML and CSS, not much else. The code is simple, and yet maintainable. No need for hooks, useEffect, useState, useMemo and all that crap.
How can you ever be sure that your state is valid when you’re putting it on the DOM? Worse yet, only parts of the state is stored there.
I can’t really call this code simple since it had to resort to timing hacks to get its functionality in order. A random 250ms delay and bam, bugs you cannot reliably reproduce
I'm not sure what timing hacks you're referring to - using setTimeout() with 0 delay? I think that's being done to defer execution of heavier functions and let other timeouts be handled first. Seems more like an optimisation rather than a hack to achieve basic functionality.
The first file I looked into was the combo box. This is what I consider to be a timing hack:
private onDropDownMouseOver(ev: MouseEvent): void {
if ((new Date()).getTime() < this.whenScrolled + 250) {
// We automatically get a hover event when we scroll, ignore it in order to keep our current highlight.
return;
}
const element = ev.target as HTMLElement;
if (element.classList.contains('combo-dropdown-item')) {
addClassExclusively(element, 'combo-highlighted');
}
}
Some event stores the time it has been fired, and this method checks that it has not been long since the firing. With react, which item has the highlight would have to explicitly be in the state and completely remove the need to do this optimization.
And this is an example of what I consider state being stored in the DOM:
The view has logic that depends on whether the dropdown is visible, which is checked by dropdown.style.display !== none. Now any element in your page has the power to modify this component’s logic by modifying the DOM
The timing hack is a workaround for a browser bug. The exact same hack would be required in React as well. What is this browser bug I speak of? Browsers send a spurious "hover" event when you stop scrolling, so that the item under mouse can be highlighted. This can cause problems in some cases.
> Now any element in your page has the power to modify this component’s logic by modifying the DOM
If some part of your application intentionally does something wrong, it can break your application whether it is React or some other tech. In this particular example, if you prefer, you can have a member variable to keep track of whether the dropdown is visible or not. Still no need for React.
As you can see, none of the complexity of React is necessary. No need for hooks, useEffect, useState, useMemo and all that crap.
Would it, though? Keyboard event sets highlighted item key/id; scroll event pops up, sets the highlighted item again, then react does not do an additional render because the state has not changed since the keyboard event.
The code does not have any complexities of hooks (which are just a javascript approximation of do notation, I don’t believe it is that complex), but what it does have is the requirement to write down all of your mutations correctly, where every “down” is an exact opposite of the “up” and does not leave any artifacts—with no way of formally checking. At least for myself, I think that level of discipline is unreasonably high so I tend to prefer stricter typed functional solutions where the view is composed purely from the state
We’re coming at this from different mental models.
The code you linked is what React helped me get away from. There’s multiple files in different folders for one screen. It’s hard to see how it composes, which is a useful boundary as it lets me know in the scope of that part of the UI.
UI is _hard_. There’s complexity that needs to go somewhere, and I’m one of those who prefer to push as much if it that isn’t business logic into a framework.
This becomes exponentially more important for every engineer you add. Go success is along these lines, with typically only one way to do things it’s much easier to share code.
From the code you linked, I could find my way around, but piecing it all together took a lot more work than any of the frameworks.
You mention only needing to know JS, HTML and CSS. But you missed that you still need to know how all that code is put together, what calls what. How it updates. React needs this too, the only difference with it being a framework is that knowledge transfers to a different project.
And to be clear, I’m not saying you need to use react or a framework—going your own way is often how amazing new things are found.
What I am saying is your attitude isn’t helping you here. React is still arguably the most used framework[0]. There’s a reason so many of us like using it and it’s what you described as “other crap”.
Frameworks help with collaboration, in the same way programming languages do. To do anything interesting with a general purpose language, you’re either going to use a framework, create a new one with good documentation and build a community of engineers around it, or build a halfbaked one that few people understand.
I’m open to other ways of doing things. It’s a good way to grow. I learnt SwiftUI a little while ago, and while I don’t use it regularly it improved my understanding of UI building. I learnt imperative UI API ages ago, and know for sure I want to avoid/contain that into a more manageable declarative approach.
It is idiomatic JavaScript. If you learned Java at the university you'll immediately be comfortable with the code. Now consider React with hooks. It is neither OOP nor functional and it looks alien to anyone who knows idiomatic Java or JavaScript. Would you recommend a youngster learning programming to learn React? I wouldn't, because it is so frankenstein. This article makes that point better than I can: https://medium.com/codex/can-we-all-just-admit-react-hooks-w...
JavaScript brings together so many paradigms, I can see strong cases for multiple different expressions of the language.
We didn’t have classes until ES6. And they’re not real classes, they still use prototypical inheritance under the hood.
If you want truly idiomatic JS, you shouldn’t be using classes. You should only be writing functions, and build your class-like objects with prototypes.
On a practical level, I absolutely recommend new engineers learn React. The job market is enormous, it’s a skill the market still rewards well.
And it’s a very productive framework. It rewards you for learning it, with better collaboration and velocity.
I would say the same for the other major view frameworks too, but React still has the biggest job market.
Until ES5, the industry thought JS was a Frankensteinesque monster.
Until maybe 5-7 years ago, anything that wasn’t OOP was considered a bit weird.
Calling any of these languages weird, is like policing English speech. We borrow so much from other languages that’s words have multiple meanings. Pronunciation follows contradictory rules, and regional dialects can be hilariously incompatible.
There’s a few languages closer to French, which has a strict control on what the French language is. For example, Go. There’s really only one paradigm them, only one way to do things.
Like it or not, pushing the boundaries of language design and framework design is how we improve as an industry.
You can’t not like a new thing because it’s weird at face value. You risk missing the forrest for some moss on a tree, and being left behind.
And sorry, that’s the same article this comment thread spawned from. I didn’t find it convincing at all, it’s let down by a lack of understanding in a few key areas.
I love how you do React. I mean, what's more react-y than blanking the page then appending HTML? I'm gonna call that Rejqueryact, because it's jQuery inside React.
I'm not seeing React being used, though, just TSX/JSX? All the view and state updating is being done manually, but it looks fairly well-organised. There are small optimisations like debouncing onInput with a timeout (avoiding rapid re-rendering/reacting to every character typed): https://github.com/wisercoder/eureka/blob/master/webapp/Clie...
Is this really much more complicated to implement than the equivalent implementation in React? (It's probably a bit more responsive, at least.)
I think they’re referring to how Reacts mental model is to wipe the page and rerender. The earliest versions basically did that, and then they started diffing and applying the diff.
They're referring to a specific bit of code in that Eureka repo that sets innerHtml = "" and then does .appendChild(). They just apparently didn't notice that the code doesn't use React at all (and is meant to demonstrate the use of vanilla modern JS without React).
No. The point of FP is "minimize state and effects so that the code is easier to understand", not "write it in FP style so that by magic is correct".
For exactly the same reason OO is "put the code that manages the state near to the state and split it in manageable parts" and not "dog inherits from animal therefore the code is correct".
Leave the faith at the church and approach code with science.
No matter how sophisticated the language we use to describe it: it’s still a bunch of side effects and state.
If you’re fetching some data in a useEffect you might not get a result that day.
If you’re updating something with setState, you are still managing state. UseState is a reference to a mutable object now.
You’re simply not getting the same answer every time your now impure function is called.
In order to do understand what’s happening you need to recreate the whole state. Which is exactly the same reason state management is hard as in OO or procedural.
You might have a mental model that explains why it is still FP, but for all practical purposes of that paradigm it isn’t.
But it’s a powerful escape hatch like rust’s `unsafe` block. Rust can do amazing things to ensure safety of your program, but there’s still times where a human can do it better.
By signposting that, keeping it to limited blocks, and wrapping it up in a safe function you get the capability to do hard things, while exposing a safer API.
useEffect is similar, it lets you write the imperative synchronisation logic. For example if you need to interact with a DOM element that only has an imperative API, someone needs to do the work somewhere to wrap it in a declarative one. You can do that in a component with a useEffect hook, and then expose a declarative API.
It's still using the useEffect hook, but just wrapped in a useFetch or something. So technically you're not building a UI without useEffect, just hiding it, no?
Because at some point your function call is manipulating registers on the CPU. If we go even further, the CPU needs to load its next instructions and then the data required.
Point being, we abstract and encapsulate complexity and provide a simpler API around it. It’s the only feasible way to manage the inherent complexity.
React builds up a virtual description of UI. react-dom and react native take that description and synchronise it to the UI layer.
If you need to do something extra, that they don’t handle like managing a map widget (ie mapbox) in React that only has an imperative API, it sure would be nice to do that yourself.
You can build a UI without useEffect. You can hide messy implementation details inside a well tested component, and contain where useEffect is being used.
And, you can understand how useEffect works so that you can use it without it having a negative effect on you.
It's just that "You can build a UI without useEffect."
and
"You can ... contain where useEffect is being used."
are not the same statement. Maybe I'm being pedantic, but when I read "build without X", I think there is some method that can be used to avoid X, not that I can hide away X.
They’re not the same statement. Both are correct. But as always, the nuance is critical.
All declarative code eventually runs something imperative.
And anything non-theoretical is going to have side effects somewhere.
Painting to a screen is a side effect.
Reading a file is a side effect.
Software gets messy when it intersects reality.
But, we can do quite a lot by staying in a theoretical realm. You can build a whole UI in the theoretical realm, where no side effects exist.
When you actually need to run it though, you drop out the the theoretical and into reality. Now there’s side effect’s everywhere.
So you contain them. Encapsulate those side effects into composable blocks. Test them extensively. Offload that work to someone who’s just focussed on managing them.
Updating the DOM is a side effect. Making a network request is a side effect.
Contain them, test them, and then you can stop thinking about them.
If someone else has done all the work to contain side effects, you can build a UI without them.
From what I've seen that's like saying you need to use salt to be a good cook while pouring a bucketful on a salad. Perhaps it's technically true but from what I've seen you can build pretty complex UI without useEffect if you follow the rules.
You have to use it, obviously, but it should be used for side effects primarily. A good indicator is if all the values in your dependency array are react props/state, you're doing it wrong.
I am not sure I am following. Say your homepage has a link to a page that shows the top scorers in a league. Where/when does the fetching of the top scorers happen ?
- (The view may change to indicate you're loading the top scorers, if you want, that's a different matter).
- Receive the data, the view changes to display the data
This is opposed to:
- Click the link to show top scorers
- View changes to show top scorers component. A component loads, or mounts, or inits, or does something which triggers a data fetch
- Receive the data, the view changes to display the data
Your app "knows" you need the data when the user clicks the link, no need to involve the view components into this.
This gives you the ability of adding a lot of complexity to how you fetch the data that is best handled outside a UI component (like caching, reusing it in other components, error handling, retrying, throtling, whatever), while saving you from a whole class of problems where a misunderstood component lifecycle has consequences for your data. Frameworks like React or Angular are going to try to help you by caching outputs, reusing components, dropping updates for the same frame, prerendering, preloading or anything really. If you fetch data when a component does any of that, suddenly you have to care about it and fully understand it. The abstraction leaked. If you treat the component as close to a pure function as you can, things become much simpler.
This applies to relatively big, relatively complicated apps, controlled by a single entity, where it pays off to prioritize simplicity.
> - how is the data fetch completion signalled to the component?
> - how is the data piped into the component?
Both have the same answer. When you fetch the data you put it in the state, and then you render your components based only on that state.
If we're talking React the state makes it into the component through the props (pure UI component) or, if using Redux or similar, some kind of hook that triggers a rerender when the store changes (useSelector? My React-Redux is a bit rusty).
The point is not to worry anymore about change detection and rendering, because the framework takes care of it by being either fast enough that it can run on every change, or smart enough that it can tell when it's not necessary to re-render (caching, change detection).
Of course, this setup with redux etc makes a lot of sense for bigger apps with lots of state coming from different sources. I don't have any specific example I can point to, but any redux implementation examples could help. I use NgRx with Angular, and the docs are OK at explaining the flow of data.
The example you highlighted as "doing it wrong" is pretty typical for an autosuggest component: Input updates trigger some request, which propagates to some list somewhere else in the dom. As it's loading, a spinner is shown, but when results are retrieved, they're updated again. Throw in apollo to the mix or some other request library, and context is used.
Absolutely not only to user inputs, but any kind of event: response, websockets, push notification, worker task finished... a million things beyond the basic "click".
> If that function isn't pure you're gonna have a bad time.
Hooks let you deal with "component lifecycles" which make that function not pure. Only the most basic toy react components are pure, everything is about side effects IN your views.
>Things get more complicated when you start using React Context and start signalling updates in a parent component. The render cascades. Maybe one component fetches some data, some component remounts, and you run your state update again, delayed by a few seconds.
This is just doing it wrong. State should change in response to user inputs. Ultimately, React is f(newState) => UI. If that function isn't pure you're gonna have a bad time. It's hard to blame anyone though. The docs suck and most of the tutorials you find get it wrong one way or another.
That said, there's kind of a reason why functional programming isn't more popular. It can be hard to grok and there can be a significant performance overhead. There's also a reason why this sort of implicit programming isn't as popular as imperative style. It's hard to predict what the implicit behavior is and footguns abound.