6 ms·
> Hooks are better because they allow you to reuse component logic, impossible with class components I've heard this said before, but I don't understand. Coul
by recursive 4y ago
> Hooks are better because they allow you to reuse component logic, impossible with class components
I've heard this said before, but I don't understand. Could you give an example of component logic that can't be reused under class components?
- codeptualize 4y agoSure! It's generally about "stateful logic". Basically logic that relies on state and/or the lifecycle methods (componentDidMount, componentDidUpdate, etc) as with classes those are only available as part of a component. You can "sort of" reuse component logic with classes, the most common way is by using Higher order components (see https://legacy.reactjs.org/docs/higher-order- https://legacy.reactjs.org/docs/higher-order- components.html). The example in that article is pretty good: Subscribing to some external data source. That requires on mount, state, and on unmount. Using HOC's is not actually reusing logic though, it's creating more components and wrapping them to compose the logic. It's a workaround. HOC's have a bunch of downsides, imo the most obvious one is the props; you need to pass the previous props, and merge in the new ones. That can create conflicts. Another typical one is refs. You need to be very meticulous about structure and how you compose and order your HOC's to make sure it all works. In hooks you can define this stateful logic truly disconnected from a component, resolving a lot of the issues of HOC's as you can just call a bunch of functions without impacting the render tree. The "plumbing" is much simpler. Hope that is sort of clear, but let me know if I should clarify any of this.
- recursive 4y agoI appreciate the effort, but it's a bit over my head with respect to react stuff. For instance, I'm not sure what's meant by needing to merge props. I was under the impression that you could pass a subset of properties as an argument to setState, and all else would remain untouched. I wasn't thinking of using HOC's. I've done a bit of react, but never touched them. I'm just thinking of reusing logic using the same techniques I use to reuse logic in code. React famously asserts "it's just javascript". Javascript provides a way of reusing logic, namely functions. If I have two class components that have the same logic in them, I'm imagining just putting that code in a function. This is not a sophisticated argument. There might be some reason that wouldn't work, but I don't know what it is.
- orange8 4y ago> React famously asserts "it's just javascript". I think that specifically deals with when using JSX, compared to other templating systems.
- codeptualize 4y agoWith merge props I mean passing down the local state to the next component. If you see the react article I linked it’s the injectedProps. I think this might be quite common, if you haven’t experienced HOC hell I can understand the confusion why hooks are necessary. In terms of putting it in a function: there is only one state object per component, you could pass setState around, but you can imagine what would happen if many functions call it. It’s also a lot more effort on the implementation as you would have to basically pass state, and call do some sort of update in the lifecycle methods. It would probably work for one function, but with many it will get problematic. You would almost have to write your own pseudo hooks framework to make this work in a decent way.
- bayesian_horse 4y agoYou shouldn't pass properties to setState. That's a very non-reactive kind of thing. Just use the properties directly. They should be immutable.
- recursive 4y agoI confused state and props. The distinction between the two has always been a bit hazy to me. I'm not sure what "non-reactive" means.
- bayesian_horse 4y agoA React component is supposed to be a pure function, a mapping from props+context as input into an output which is a React element plus sideeffects (which when executed by the React library will often change the context). State lives in the context. To illustrate statefulness: If you drop a flummy ball on the floor, it will bounce back and doesn't change. If you drop an egg, it will change and you can't drop it easily again. The ball is stateless, the egg is stateful.
- branko_d 4y ago> HOC's have a bunch of downsides, imo the most obvious one is the props; you need to pass the previous props, and merge in the new ones. Render props (aka. "function as children") are much more free form than HOCs - they allow you to "compose the props" at the site of usage, as opposed to the component implementation. I don't think there is a use case that HOC covers that cannot be done with render props - please correct me if I'm wrong.
- codeptualize 4y agoYou are not wrong, I think renderprops are valid, and I still use them in some situations. They are imo not ideal as they are hard to memoize because of the render function. It’s funny that if you try to memoize renderprop components you likely have to use some sort of inputs array just like hooks. Besides the memoization issue it also gets pretty messy if you need to implement many of them. Instead of just putting things in variables you are now nesting many levels deep. I think renderprops and hooks are functionally not that different, but hooks have better ergonomics when using many.
- idreyn 4y agoI have a hook that I copy around between projects called `useViewport()`. All it does is watch the current viewport size and updates its value when that changes. Because it's a hook, I can call this function from any component body: const { width, height} = useViewport(); return <div>Viewport: {width} {height}</div> Zooming in, this is just built from a useEffect() to bind event listeners, and and a useState() to hold the current value. Zooming out, it would be easy to write a useBreakpoint() hook that mostly just calls useViewport(). Hooks compose. Before hooks, there weren't great patterns for isolating units of stateful logic from the presentational side of React. A really common pattern was to use "render props" where a component keeps some internal state and passes it into a function-as-child: <ViewportWatcher> {({ width, height}) => <div>Viewport: {width} {height}</div>} </ViewportWatcher> You'd see these provider-components nested three or four layers deep, and it got ugly. Hooks solved this.
- recursive 4y agoI'm not a react expert, obviously, but what would be wrong with this? class MyComponent { constructor() { watchViewPort((x, y) => { this.something += x + y; }); } render() { /* ... */ } } watchViewPort(callback) { addEventListener("resize", (event) => { // get x and y callback(x, y); }); } This is obviously not production code, and I haven't tried it, so maybe something doesn't work? What is this missing that hooks provide?
- idreyn 4y agoHooks let you colocate logic that, in class components, would need to be split across multiple lifecycle methods. In practice you need to remove the event listener when the component unmounts. You can get reasonably close to a hooksy API for doing this here: class MyComponent { componentWillMount() { this.stopWatchingViewport = watchViewPort((x, y) => { this.setState({ something: x + y }); }); } componentWillUnmount() { this.stopWatchingViewport(); } } watchViewPort(callback) { const onResize = (event) => { // get x and y callback(x, y); }; addEventListener("resize", onResize); return () => removeEventListener("resize", onResize); } But being able to slice up logic by functionality, rather than by lifecycle event, gets gradually nicer as you have more of it.
- mikeryan 4y agoTake a look at Use hooks libraries for examples of code that you may want to have portability with (this is they typescript one because its the one I've used) One of the simplest examples is "useToggle" which just sets a state variable to true or false. Not hard to write in a class component but it's still stuff that you may end up writing a lot. A lot of similar ones are click and event handlers that need to be cleaned up after the component is unmounted. useIsMounted is one I use a lot too to ensure I'm not trying to write state on an API callback once a component is unmounted. You could add each of these to a class with an hoc and end up with withToggle(withIsMounted(withUseMediaEvent(MyComponent))) but that tends to be a bit of a mess. https://usehooks-ts.com/ https://usehooks-ts.com/