4 ms·
I hates the idea of hooks. After trying them, there are things are like about them, and I use them. But it's not "the best things to happen to react". It added
by BiteCode_dev 5y ago
I hates the idea of hooks. After trying them, there are things are like about them, and I use them.
But it's not "the best things to happen to react". It added plenty of complexity to the system.
Hooks have been embraced by the community in a way that now many features only exist as hooks, which makes ones life difficult as soon as you don't want to use a functional component.
An no, not everything should be a functional component.
In fact, some things are really hard to do with hooks. I dare you to craft a simple reusable _and correct_ useInterval() hook without stealing the solution online.
Go on, I'll wait.
- jitl 5y agoI think your exercise framing is silly but I’ll bite since I’m a programming addict. Writing on my phone so forgive any typos. function useInterval(cb, ms, deps) { useEffect(() => { const id = setInterval(cb, ms) return () => cancelInterval(id) }, [ms, …deps]) } I think this is much nicer than having interval maintenance and prop diffing is didMount, didUpdate, and willUnmount. Certainly it’s easier to get the hooks right (for me) and all the logic ends up in contiguous lines of code. It’s a higher level interface so it takes a bit more practice to apply - feels like Ocaml more than Java.
- stevebmark 5y agoI think the original comment is fair, and comparing your attempt to working solutions online will reveal the complexity of bugs that can arise from hooks.
- jitl 5y agoI see - the issue with my solution is that the interval will reset whenever the deps array changes, starting over the delay? The implicit "state" of the time left before the next tick is destroyed when the effect re-runs - instead this should persist. Dan Abramov has a good post that explains the issue here well: https://overreacted.io/making-setinterval-declarative-with-react-hooks/ https://overreacted.io/making-setinterval-declarative-with-r...
- BiteCode_dev 5y agoAlso the id must be hold using useRef(). That's the whole problem with hooks: when things are easy, they are nice. When things are complicated, unfortunately, they look easy, and you start to think you understand what's going on. But most people, me included, don't.
- tuan 5y agoI don't think you need to hold id using useRef(). The cleanup callback holds the id from the same render, so it will clean up the correct interval.
- jitl 5y ago> When things are complicated, unfortunately, they look easy, and you start to think you understand what's going on. But most people, me included, don't. That’s fair. The other side of the coin is that class components have their own kinds of failure modes. I have fixed a lot of buggy class components that simply forget that props change - they do some kind of effect-y thing using the first props during didMount, and then never respond to prop changes aside from `render()`. With hook components, the linter will get mad about that sort of thing. In either case there’s gotchas, but I like that useEffect helps people avoid leaking and think about changing props.
- thatswrong0 5y agoI don't find the correct class component implementation to be any simpler. You have to worry about the exact same issues (clearing on unmount, potentially canceling + calling again if a prop dependency changes), except now the implementation is spread across multiple lifecycle methods. I've seen people reimplement it wrong in my codebase more than once, whereas no one gets useInterval incorrect because.. we can actually share that functionality across components now.
- wruza 5y agoAs I read this thread I feel helpless and not sure where to ask it, so excuse me that it is after your comment. Why do react guys choose to fight these battles in the first place? We had a clear model, MVC (not web 1.0 mvc which left MC at the server-side, I mean fully-in-app one). All these setups and teardowns were done in “C” part, which didn’t depend on how exactly views are [re]arranged on the screen. And all interactions went through C, leaving little to no state in V (only very local ones, e.g. whether a combobox shows a popup currently, or is there a div-tooltip above a label). Then react broke in and told us that all we have is views/components and got a grip on their lifetimes, forcing us to jump through these hoops. And that functional-async thing was not even the reason for that. React could have the same “off-screen” controllers with explicit lifetimes and setState() and friends, to be more testable and composable and all of that. But they chose to push all state to transient objects and then began to heroically solve the mess created by themselves in the first place.
- thatswrong0 5y agoI think I get what you mean (lmk if I don't). But there's a reason why libraries like redux can exist: React is _not_ a framework and doesn't impose many restrictions on how you choose to structure your application. My current company, for example, enforces a pretty strict architecture where core application state lives "outside" of React [0]. What page we're on in our SPA, for example, is determined by state in our page store. We don't explicitly rely on component mounts to fetch data - instead, when we switch to a certain page via some action (like OpenUserPage), and _that_ fetches the data needed for that page. When we navigate away from the page, we call CloseUserPage, which unloads that data. We try to push all business logic into discrete use case based actions. Like you mention, we use local component state strictly for view state (e.g. is this menu open?). We try to use hooks like useInterval sparingly (I think we only use it for things like updating relative timestamps every minute). We do use setInterval in business logic though, where it's simpler to reason about, for stuff like polling. In an ideal world, there'd be very little need for complex hooks, where most components are strictly function components that only re-render when state that they're subscribed to in the store changes. But the real world is messier, and making a beautiful SPA with animations and whatnot often requires tricky view state logic with hooks. And of course, you have to be careful to not re-render components unnecessarily in performance critical situations where you're rendering a lot of stuff. But I think the sort of high level separation you're describing can and does exist, and IMO striving for that separation makes it much easier to understand how data flows through the app, and obviates the need of digging into component lifecycles to manage the state of the app. [0] At the end of the day, it does live in a top level context, but we don't interact with that context directly from child components.