6 ms·
While I personally like React, I have to say the design of the library is just so awful and non-intuitive. While I can maintain a legible codebase myself, as so
by worble 4y ago
While I personally like React, I have to say the design of the library is just so awful and non-intuitive. While I can maintain a legible codebase myself, as soon as juniors in my work are involved I have to spend a lot of time reviewing PR's, fixing changes and explaining concepts in order to make sure that the application actually runs correctly and isn't, say, infinite looping in a useEffect or something like that.
I only rant about this here because I think useCallback is pretty awful design - separate functions that only exist as syntactic sugar are terrible for user readability. A lot of people probably know useMemo as it's quite easy to understand and used somewhat frequently, but if I were to use useCallback in my code it would probably cause a lot of others at my work to then have to go scouring the docs to figure what the heck this hook exactly does. On the other hand, just forcing users call useMemo and return a function means that everyone who knows useMemo knows what's happening.
Unless I'm completely misunderstanding how useCallback works, perhaps React actually does some extra optimization under the hood or for this or something.
- michaelsalim 4y agoWhile I agree with with that useEffect can be non-intuitive and easy to misuse, I think useCallback is pretty nice to have. From what I'm aware, it's as you said. It's simply a syntactic sugar for useMemo if you want to memoize functions. Now if useCallback doesn't exist, you have to use useMemo and pass in a function to the function. Something like `useMemo(() => () => ...)`. Sure if you know what useMemo does then you'll know what it does. But I have a hard time believing that juniors would find that easier to read than useCallback(() => ...). All I need to say to them is: "Hey, if you want to memoize a function, use useCallback instead". And if I see useCallback used anywhere, I know for sure that it's memoizing a function. Rather than saying: "So you see that there's an extra bracket there? That means that you're returning a function. Yada yada" There's a grand total of 15 hooks[1], most of which you probably never ever have to use. I would expect all React developer to go through them all to see what they're about. I would also expect them to know & remember most of the basic ones: useState, useEffect, useContext, useReducer, useCallback, useMemo and useRef. That's a total of 7 functions. If they can't do that then I question the quality of today's developers. [1] https://reactjs.org/docs/hooks-reference.html https://reactjs.org/docs/hooks-reference.html
- epmatsw 4y agoI’d argue that useReducer and maybe even useRef most people could get away without knowing.
- postalrat 4y agouseRef is pretty important. useReducer though could be removed and I wouldn't notice.
- michaelsalim 4y agoI'm inclined to agree with you since I don't use useReducer as well. But there are projects that are littered with that -w-
- ummonk 4y ago> I would also expect them to know & remember most of the basic ones: useState, useEffect, useContext, useReducer, useCallback, useMemo and useRef. That's a total of 7 functions. If they can't do that then I question the quality of today's developers. Exactly. I’d rather write the code myself than have to review the code of someone who can’t understand such a basic set of concepts.
- mmmpop 4y agoBut see, you're not thinking enterprise.
- foomatic 4y ago"useCallback" is not very intuitive naming. I'd guess a fair bit of the confusion could be attributed to this alone. Could have been useMemoizedValue useMemoizedCallback at least. The whole useXXX naming convention is also unintuitive.
- adamredwoods 4y agoOr the term "side effect" (especially in a language that does not enforce return types): https://dev.to/ruizb/side-effects-21fc https://dev.to/ruizb/side-effects-21fc
- cageface 4y agoReact works great for simple examples and small applications. When you try to build something complex with good performance then the difficulty goes almost vertical. It’s trivially easy to miss or break a stable reference somewhere and tank performance or show stale data.
- acover 4y agoI converted a long list from Django templates into react. I struggled to convert the code to navigate to a hidden element. In JavaScript it's document.getElementById and set attribute. In react it's easy to cause part or the entire list to recalculate the virtual dom. I couldn't think of a good solution. Ideally I'd just call set state on the child element that needs updating but that would require registering all the relevant functions with the parent. Super ugly.
- solardev 4y agoCan you explain? Are you saying there is a long list, with some hidden elements that need updating (but not rendering)? If so... can the entire list be stored in state (and updated as necessary), but only the ones marked "is visible" actually get rendered? Maybe I'm misunderstanding completely...
- acover 4y agoSo in Django templates I'd just flip a style - display from hidden to block of a single div. This would reveal a collapsed section of the tree and I could scroll to the correct div id. (saying list was a bad simplification) In react because the state flowed from top to bottom I have to be very careful about what objects I update. Just passing down a single reveal could force the virtual dom to update for (num children per node)*depth. Even this required care on what props got updated. The solutions seemed to be: 1. lots of useMemo so only a minimal amount of a node got recalculated; 2. Directly call a set state function of another child. Both are quite ugly :( but the second seems nicer as it never could force a full update. However, it seemed to require a registry of set state functions {id: setState}.
- 4y ago
- petilon 4y ago> I have to say the design of the library is just so awful and non-intuitive. Absolutely agree. But this wasn't always the case. The original class components were much easier to understand. A backend developer could open a .tsx file and understand what is going on, and make simple fixes. This was one of the strengths of React - it was so clean, compared to Angular and other frameworks. But then they introduced hooks and messed it up. Now it is not intuitive in the least. Hooks makes some things easier but the cost in terms of loss-of-intuitiveness is huge. The other mistake Facebook is making is assuming that performance is the most important attribute of a UI framework. It is not. For 99.9% of developers the original React was already fast enough. They should have focused on making the mental model cleaner, and smoothing some of the roughness of the lib such as updating the props of a stateful component, handling deeply nested objects in the state without making entire copies of the data and so on.
- HeyImAlex 4y agoI don’t think it was done for performance, hooks just compose much better than class components. Definitely a trade off in terms of blank-slate intuition, but it unlocked a lot of things in the realm of reusability.
- foomatic 4y agoWhat does "compose much better" mean?
- HeyImAlex 4y agocopy/paste from another comment: Hooks compose, whereas side effects and memoized values sprinkled through component constructors and lifecycle methods do not. For example, the equivalent of useEffect required calls inside of componentWillMount, componentDidUpdate, and componentWillUnmount. You try and make something like this re-usable and you’ll be leaking details of your implementation across the whole component via inclusion in these lifecycle methods, not to mention any data you’re shoving onto the component instance. But it’s still doable. Now, what if you wanted to use this re-usable behavior inside of another re-usable behavior? It gets complicated fast! Now your library needs to expose the lifecycle-updating methods of the underlying library, leaking details all the way down. Hooks are opaque from the perspective of lifecycle, while still having access to all the same… hooks.
- ilrwbwrkhv 4y agoJust use imba and get much better performance and dx without the pain.
- boredtofears 4y ago> as soon as juniors in my work are involved I have to spend a lot of time reviewing PR's, fixing changes and explaining concepts in order to make sure that the application actually runs correctly I've never worked on a codebase where this isn't true regardless of what frameworks or libraries are used - that's kinda part of the gig.
- amand33p 4y agoExactly. I don't know why people pick on only React for this. Any un-opinionated library or toll will have the same problem.
- solardev 4y agoIMHO (only), React is a bit too flexible/modular/unopinionated and asks you to reinvent a lot of wheels... everything from basic page routing to syncing ajax calls to loaders and states, etc. More opinionated or bolts-included frameworks have defined conventions that you're strongly encouraged to adhere to, and they work great for most use cases. And when you see that pattern again, you know what the intent is. But with React, every dev ends up doing the same thing their own way, with subtle differences and subtle bugs, and then as turnover happens and frameworks become less fashionable, codebases get polluted by a mix of different dev and tool generations and it gets even harder to ensure correctness. Using a more opinionated framework built on top of React, like Next.js, can solve a lot of those issues... until Next itself becomes unfashionable and the cycle starts again :(
- scrollaway 4y agoYeah React is not meant to give you this layer. NextJS indeed does. Why do you care if it becomes unfashionable in the future? Pick one tool that fits your use case and run with it for its lifetime. If you need to learn something else 5 years from now, learn something else. I’ve been in software for two decades almost, I’ve always had to learn new frameworks and libraries, part of the job isn’t it?
- 4y ago
- acover 4y agoIsn't useCallback to solve the common mistake of: <button onClick={() => setText("clicked")}>click</button> Without useCallback this would update the dom on every render.
- littlecranky67 4y agoUnfortunately the "update on every render" is deeply anchored into devs minds, although in most cases play a minor role. It comes back from a time where browser JS engines where really slow to create lambdas - which is not the case anymore. Additionally, react doesn't really update the DOM on "render" (the internal react render cycle) - due to DOM diffing. My best advice is (also apart from React): Do not spend time on imagined/anticipated performance bottlenecks; only ever spend time on performance tuning if there are real (perceived, not measurable!) performance issues (there has to be a profiling report in your hand).
- acover 4y agoYeah I only started caring about this when tracking down lag in my app. Though it's fun to think about :) I believe this causes a real Dom update because it can't know the onclick function hasn't materially changed. It's just diffing function references.
- graftak 4y agoThe main use for useCallback is to add a callback to a useEffect dependency array without it running on every render.
- darepublic 4y agoThat's not a mistake lol.
- acover 4y agoCan you explain why it isn't? I'm probably misunderstanding something. setText doesn't change because it's from useState. The only reason to update the Dom is because the onclick function isn't memoized. Updating the Dom every render isn't terrible but it isn't good.