Hacker News new | past | comments | ask | show | jobs | submit login

Also: even with hooks, the component is still a pure function in a less low-level kind of way.

The hooks yield effect descriptions, to be carried out later, on a side channel. So the component is still a pure map of the inputs to the outputs, just that the outputs are not just comprised of the javascript function's return value, but also the effects on the side channel.




Any function is a pure function if your consider the entire program state as your input and output.


You really don't need to give hooks access to some global variables (or all of them). You can, of course. But you would actually do that in a useEffect or use some setState in a callback somewhere.

It's a cheap shot to complain that Javascript isn't a purely functional language... React can be used in a pretty pure way and if you don't you'll don't get the full benefit.


I see you've discovered the IO monad in Haskell.


That’s not pure anymore for any practical definition.

When you get different answers for the same question, then you’re not calling a function.

When you can only get the same result by recreating the same internal state through external manipulation, you’re dealing with side effectful, imperative code.

Hooks are ergonomic and easy to reason about and that’s great. But they turn functions into objects.


What you’re missing here is that the hooks form part of the input to the hook/render function. There’s a reason they can’t be conditional (though with a compiler theoretically they could be).

The whole idea of the useState hook, is that it’s _not_ internal state to the hook. That state isn’t stored on the stack of the hook function, but against the component.


I understand that, but your component is now an object that can be mutated via events and it tracks internal state via calls to useState.

You cannot call the component with the same arguments getting the same results anymore AKA it’s not pure. You indirectly mutate it via event handlers, which are effectively methods.


no, it can't be mutated by events. The hooks only react to inputs in the side channel and only during execution.

If you attach an event handler, that "attaching" is an effect and executed outside the rendering. If the handler changes some state of the context, a rerender is triggered.


We're either talking about two different things or you are missing the forest in the trees.

The value proposition of FP doesn't come from whether you feel like you're doing FP during implementation. It can only be assessed from the perspective of the caller. The caller doesn't care about the philosophical differences of how you achieve internal mutation or the implementation thereof.

They only care about whether you are returning the same result when they give you the same arguments. That's how you satisfy a function interface.

A component that keeps track of internal state with useState and modifies it via event handlers does not satisfy a functional interface, because given the same props, it may or may not return the same docoument fragment.

One cannot pass in the same state, nor can one see the state from the return value. The signature of a component that uses useState and event handlers to modify it, _hides_ internal state from the caller. A component like that doesn't satisfy a functional interface but does in fact hide an object interface via local retention and message passing.

Vice versa, a component that bangs on an internal variable in order to derive/calculate values that it returns, can satisfy a functional interface from the caller's perspective. Similarly you can use useState and useEffect to implement a functional interface. It all comes down to whether you are giving the same answer for the same question, which is typically not what you're doing with hooks.

Note that I'm not making a value judgement about whether a component is a function or an object (via hooks). If you need an object, then write an object. But be aware of the tradeoffs of writing a function vs an object and be upfront about it to your caller.


It's really just a question of definition and Perspective. From the perspective of the JIT or Assembly, there's no such thing as FP. So you got to make abstractions.

And a very helpful abstractions is to say that the context that you are saying is impure is just another parameter and another part of the return value. Because that's how React is treating context, and that's why you can treat React components as functionally pure if you respect the rules of hooks.

FP doesn't demand the parameters stay the same. It also allows for outputs of a function to get put back in as a parameter in a subsequent invocation, which is what happens to the context. If you insist on seeing it another way, I can't stop you, it's just more complicated and I don't see how that's helping.


> FP doesn't demand the parameters stay the same. It also allows for outputs of a function to get put back in as a parameter in a subsequent invocation, which is what happens to the context.

My point is that _you as the caller_ are _not_ doing this when calling a stateful component Foo. Foo mutates between events and state is entirely encapsulated, so you are getting different results from the same question. The caller doesn't care about the internal execution model of Foo and React. A functional interface is _only_ satisfied if the function is referentially transparent. Which in this case it is not.

If all you can do is send messages and observe behavior from outside. It behaves exactly like an Object and not like a Function from the perspective of the caller.

---

You are arguing in terms of the implementer of a stateful component. You are thinking in terms of how React/useState behaves from inside your component and further up the call stack. And in this context I agree. You can think of useState as part of your signature so to speak. In fact the hooks rules prevent you from doing things that violate this mental model.

But that's not what I'm talking about. I'm talking about the practical, real world perspective of a caller and whether they observe functional or object oriented behavior from your component.


> hooks form part of the input to the hook/render function.

They are input, but they are not input parameters.

A function is pure if it returns same result for same input parameters. Hooks make it possible to return different result for same input parameters, therefore making the function impure.


Again, no. Functional components are not defined by just their "javascript function" but rather by the contract with the rest of the rendering system.

And that's why the context manipulated by hooks looks like a sideeffect, and it often does describe sideeffects, but it doesn't. That context is both an input and an output, only the rendering logic in React decides what to do with that output. Without the rendering logic deciding to execute those sideeffect, the context isn't actually changed at all. Which is why you usually don't need to care about when or how often the component is executed.


From https://en.wikipedia.org/wiki/Pure_function: "the function return values are identical for identical arguments".

The whole point of pure function is that the caller can understand its dependencies without looking at its implementation, because all dependencies are listed as parameters.

You can redefine what "pure" means if you wish, but that pretty much defeats the purpose.




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: