6 ms·
I personally fell in love with hooks after initially disliking them, you should give it a try, maybe in a toy personal project, to see if you like it. It is gre
by enlyth 5y ago
I personally fell in love with hooks after initially disliking them, you should give it a try, maybe in a toy personal project, to see if you like it. It is great for separation of concerns.
You basically stick to writing pure functional components focused only on how to render, and try to abstract reusable logic into hooks, and expose only what you need
For example, you could make a useApi() hook and inside your component just do const { data, loading, error } = useApi('/endpoint'), so you can hide everything you don't need away from the rendering logic
- flowerlad 5y ago> pure functional components focused only on how to render, and try to abstract reusable logic into hooks Just FYI, once you add hooks, it is neither pure nor functional. https://mckoder.medium.com/why-react-is-not-functional-b1ed12a41323 https://mckoder.medium.com/why-react-is-not-functional-b1ed1...
- WorldMaker 5y agoThey may not be pure, but they are still functional. The hooks follow similar laws to Monads. They aren't entirely monadic and it would have been nice if they were and used a more monadic combinator for bind [1], but they are a relatively pragmatic solution for a language without a strong type system to encode things like algebraic effects and monadic bindings in. [1] Mostly useless aside: using a .then()able based plumbing would have opened up the possibility of using the async/await combinator language. The names async/await would give the wrong impression especially prior to the actual concurrency changes to eventually ship in React 18, but would have potentially been a more monadic fit.
- flowerlad 5y ago> The hooks follow similar laws to Monads. And monads are impure [1]. If all your functions are impure then you're not doing functional programming. [1] https://alvinalexander.com/scala/io-monad-doesnt-make-function-pure-obvious-impure/ https://alvinalexander.com/scala/io-monad-doesnt-make-functi...
- WorldMaker 5y agoYes, I stated that. Those functions are impure. Purity is a lovely goal, but purity also isn't a defining characteristic of functional programming, it's a modern pursuit. I've met enough classic LISP practitioners that lived their whole programming lives in the most impure of functional programming, that I would never want to tell them to their face that what they did didn't count as functional programming because of all the leaky impurity in LISP (due to pragmatic considerations of the time).
- flowerlad 5y ago> purity also isn't a defining characteristic of functional programming Disagree. It is in fact the defining characteristic of functional programming.
- e12e 5y agoIt may be defining of pure functional programming. But not for "functional programming". Some arguments for why (and indeed some discussion for why not, too !) : https://wiki.c2.com/?FunctionalProgramming https://wiki.c2.com/?FunctionalProgramming Ed: and I suppose if a function call allocates a stack frame it's no longer a pure function? Or are all functions of type crash-or-value?
- 1_player 5y ago> monads are impure Not necessarily. The IO Monad (Haskell et al.) is impure, a monad is just a functional abstraction that doesn't have anything to do with purity at all.
- bern4444 5y agoIf you get really technical, any program is impure as running the code has the side effect of increasing the temperature outside the cpu from running the program. That's a side effect. And running a program is going to change the temperature in a different way each time That's to say, at a certain point, all this is arbitrary. Pure code is generally easier, but a program that's only pure code is pretty useless. You always need an escape hatch which is what some monads like IO or Futures provide. Monads and other functional paradigms allow us to write and interact with impure code in a pure way and mindset. That's exactly what hooks do as does the react mindset of, your view is a function of state. Hooks easily let us separate that statefulness into their own abstraction - just as futures do for async calls, and IOs do for the file system. This lets us model our view as a function of state (and props which are just arguments to a function)
- enumjorge 5y ago> You basically stick to writing pure functional components focused only on how to render If you’re using hooks like useState or useEffect I wouldn’t consider those functional components pure. Hooks provide some nice syntactic sugar, which is not nothing, and make it easier to share logic between components. In my experience hooks have made my code easier to read, but they haven’t simplified it. The side effects and state might not be inlined but they’re still there. If anything they’ve made it less explicit because some of the details are hidden behind the magic that the React runtime uses to add state to functions.
- bern4444 5y agoI’m sure the parent author knows this But the beauty of hooks is as you say reusable statefull behavior. It also lets you treat your functional components more like a pure function in my opinion. If the hooks you use are poorly designed, then yeah, it may be more difficult. But well designed and implemented hooks make your component appear more like a pure function. The state is (more) decoupled from the UI code than before and lets me easily reuse behaviors across components.
- nexuist 5y agoThey're technically not pure, but they're as close as we can get to functional-style state handling: declare dependencies upfront so the caller knows exactly what they'll get when they execute your function. Fully state-less code achieves basically nothing; you need to "escape the hatch" eventually to work with the rest of the architecture. Hooks are very beautiful escape hatches that let you deal with persistence without having to sacrifice the rest of your function's body to it.
- bern4444 5y agoReally well said. And if you really wanted to make it 'pure', you could easily write a hook with an explicit return type that wraps the type of the initial value. If you're using typescript, you can then limit the possible types of the generic to only monads. type State<T> = val as T; const useStatex = <T>(initialState: T) => { const [state, setState] = useState(initialState); return [state, updateState] as [State<T>, (val: T) => void]; } This new hook, useStatex, has an explicit type definition that indicates something stateful is taking place. Same as Futures. You can take this even further in the typing limiting the generic to only allow certain types for the underlying values to be monads, or even more simply type State<T> = Promise<T> | Array<T> | Option<T> So you avoid an extra layer of nesting like State<Future<Array<T>>> Point is, there are lots of ways to easily resolve any its not pure! arguments same as any other functional programming concept eta The simplest way to limit the return type might even be to just do this const useStatex = <T extends Promise | Array | Option>(initialState: T) => {