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

“Put another way: class components have a single instance per mounted component, but function components have multiple “instances” — one per render. Hooks just further entrench that constraint. It’s the source of all your problems with them”

I see this a lot, it’s probably the misunderstanding that drives most of the dissatisfaction with hooks.

Having a single instance that exists for the whole lifetime of the mounted component was a major advantage of class components, the major drawback being that you kept losing immutability.

The big advantage of functional components is they give you all that immutability, their drawback is you no longer have a single instance that corresponds to the mounted component’s lifetime, because functions are just executed and then they’re gone (until the next time you execute them).

The way to think about hooks is that React will create a internal virtual instance that does correspond to the lifetime of the mounted component, and it will let you hook into that virtual instance from the function (to store state, effects, refs, etc). The idea was that way, you can have both immutability and single-instance-per-lifetime benefits.

Because React is managing all of these internal virtual instances itself, it can do some nice magic like letting you use a clean top-level “useState” function and it Just Works… because behind the scenes it is pairing up each call to that function with each internal virtual instance (using its order in the call stack, which means the magic fails if hooks are called conditionally, hence the rules of hooks).

That’s fundamentally the concept that lets you work with hooks fearlessly. You no longer had to provision each of your class components with their own instance and make sure they were maintaining it properly, instead your function components could just clock in and clock out and React would take care of making sure they were handed the right instance to work with.

If I had to pinpoint the exact mistake React made with Hooks, it was this: saying you could emulate componentDidMount with useEffect(fn, []). It completely obscures this idea of a virtual instance you’re hooking into. They should have been explicit about the virtual instance model and given developers “useDidMount(fn)” and “useWillUnmount(fn)” hooks, explaining that for each function component you write, React is managing an instance for it behind the scenes and React will make sure it runs the provided mount and unmount functions at the appropriate moments in that instance’s lifetime.

One can imagine a hybrid option, a lightweight class definition (so you could set state in constructor, define DidMount, make refs, etc., in the natural way) that would then return a functional component. That would make the long-lived instance explicit, but I think the ergonomics would unfortunately suck: “render() { return function (props) { return <div/> } }” is hideous, for example.




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

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

Search: