4 ms·
That's a very general statement. I wouldn't accuse you of implying that it would also apply to e.g. Date.now(), but I firmly disagree that it applies to hooks.
by Chernobog 6y ago
That's a very general statement. I wouldn't accuse you of implying that it would also apply to e.g. Date.now(), but I firmly disagree that it applies to hooks.
I get that hooks are declared in the form of functions, and that pure functions are the desired pattern in many cases. But I like to think of hooks as hooks, not functions (emphasized by the naming convention of prefixing with "use"). We are in the context of React, after all, and I think it is comparable to critique of JSX because of "separation of concerns". Yes, valid critique in many cases, but not necessarily applicable to React.
Having been a React developer for over 5 years now, I think hooks solve a lot of problems that before would typically have been solved with Redux, Redux Saga and other libraries. Or with home made solutions, leading to various degrees of mess. From what I've seen, hooks have enabled React devs to write code that is even easier to understand, while also keeping things simpler and external libraries fewer.
- nwienert 6y agoYea, it's definitely a workaround for not having algebraic effects, you can basically think of it as a yield. Of course ideally the language would have it first class, it doesn't change the fact that they are immensely useful. Having composable stateful logic that always handles side-effects is incredibly useful, and it works really well within the immutable data / top down data flow model of React. I'd love to hear the alternatives, as I spent years researching and working on many (Redux and FRP/reactions) and they're simply not as nice.
- eyelidlessness 6y ago> That's a very general statement. I wouldn't accuse you of implying that it would also apply to e.g. Date.now() You don’t need to, I’ll gladly go on record saying Date.now() is not a function. It’s a subroutine. The clearest signal isn’t even its return value, it’s the fact that it takes no input. > [... everything else you said ...] I don’t have a problem with the expressiveness of hooks, nor the general way they solve a problem by defining clear APIs for interacting with reactivity and state. I have a problem with the context in which they’re called, and the way they infect their context by changing the semantics to be sometimes else. Hooks are something you instantiate and use in your component’s lifecycle. If it were that simple, you could call them in an outer function and return a component. But because you call them while defining the component’s behavior, your component is no longer semantically a function of props, it’s a constructor. A better API would be hooks called in a component factory, returning components which use those hooks.
- Chernobog 6y agoThank you for elaborating! I remember I was really curious when they introduced them, since there had been a lot of focus in the community on stateless functional components before, and the benefits of their purity. Now suddenly they were renamed to function components instead, and as you say, are no longer guaranteed to simply be a function of their props. I guess what we disagree on is whether that is an issue or not. What problems do you feel the current hooks API is causing, that could be solved with a different API?
- eyelidlessness 6y ago> Thank you for elaborating! I remember I was really curious when they introduced them, since there had been a lot of focus in the community on stateless functional components before, and the benefits of their purity. Now suddenly they were renamed to function components instead, and as you say, are no longer guaranteed to simply be a function of their props. Thank you for engaging thoughtfully and with some curiosity! I'm sorry it took me a while to come back to this, but I do want to answer because it's worth exploring. > What problems do you feel the current hooks API is causing, that could be solved with a different API? Frankly, once you introduce hooks, you can no longer trust that a function is a function. You can't call it without knowing whether it'll cause side effects. You have to know the hooks internals to know what those side effects actually do, and you have to know the internals of every component before you consider calling a component. It's a breaking change of huge consequence, with no type-level (whether you're using TypeScript or JSDoc or just web docs) indication of what a thing is. So now, allllll functions are not functions. A way a different API could solve this would be to make the construction and render explicitly separate (just like all of the pre-hooks state APIs for react). Modifying the example from the hooks intro: import React, { useState } from 'react'; function Example() { const [count, setCount] = useState(0); --- return ( +++ return () => ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); } This isn't where I'd dust off my hands and call it a day. A more ideal hooks API, with chaining and composition in mind, would not just produce free-floating values and state update functions. You could instead wrap props and essentially have a component-local API for a props/state combination where the component still is just a function of props: import React, { useState } from 'react'; function Example(props) ({ const setCount = useState(props, (props, state) => { ...props, count: state, })); return (props) => ( <div> <p>You clicked {props.count} times</p> <button onClick={() => setCount(props.count + 1)}> Click me </button> </div> ); } A comment adjacent to yours (which I don't have time or patience to respond to right now) asked how another API would deal with hooks which are instantiated per-render (which... I guess exists but it's mind-boggling because it's not how hooks are explained to the public), take either of these examples and nest them for each state/props case you'd encounter. This is the Python principle of explicit is better than implicit (which means, yeah, writing a bit more code might be a pain in the butt but you'll understand what's happening), and in FP is referred to as referential transparency ("If I call f(x) -> y, y will always be the same for the same x").