6 ms·
I would say useEffect is not an escape hatch, it's a fundamental building block of the hooks paradigm. You need some way to run impure side effects after your c
by phailhaus 4y ago
I would say useEffect is not an escape hatch, it's a fundamental building block of the hooks paradigm. You need some way to run impure side effects after your component has been rendered, and `useEffect` is how you register those effects.
The most basic example is making an external request based on props: can't do that in the render loop because it has to be pure, since React may run it multiple times before committing to the DOM. `useEffect` is the only way you can get a guarantee that it will only be run once after rendering, and only when its dependencies change.
- paulddraper 4y agoRight. It's how mutations are done. But there is a lot of mutable code that could be immutable, and `useEffect` is how that happens in React.
- phailhaus 4y agoSorry, what do you mean by mutable vs immutable code? I don't think it necessarily has to do with mutability, because you can "mutate state" in regular callbacks without useEffect. The only way to get true mutability in React is via refs, all other state is immutable.
- paulddraper 4y agoI mean pure vs impure. > you can "mutate state" in regular callbacks without useEffect Yes, via `useState`. That too gets overused. (Note: useEffect and useState are 100% necessary, but also easily overused.) useEffect for when you want to manipulate state outside the component. I.e. change the document title, exchange data with an HTTP server, store data in localStorage.
- bayesian_horse 4y agoAlso: 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.
- dgb23 4y agoThat’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.
- ojkelly 4y agoWhat 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.
- dgb23 4y agoI 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.
- bayesian_horse 4y agono, 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.
- dgb23 4y agoWe'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.
- bayesian_horse 4y agoThe last statement isn't true unless you mean "mutability" in just the DOM elements. All sorts of things can carry state and be mutable in a React application. Even the properties of a component are actually mutable, and it sometimes happens that people pass around arrays or objects and mutate them when they shouldn't.
- phailhaus 4y agoWell, javascript is mutable so technically nothing is immutable. But I'm referring to working with React's hooks, where all props and state should be treated as immutable except for refs.
- bayesian_horse 4y agoRefs are just as immutable in that perspective. And no, you're not supposed to mutate ref.current.anything outside useEffect or a callback or similar...
- phailhaus 4y agoOf course you can! That's the whole point of refs, and why you can't use them as a dependency to callbacks or effects. They're totally mutable, which makes them very tricky to deal with. I mean, I wouldn't recommend updating them outside of effects/callbacks, but it's valid. For example: you can make a ref to count the number of times React calls your render loop by updating it in the body.
- vlunkr 4y agoThis is definitely true, but I also think it's overused in typical UI components. I often see patterns where some user event triggers a state change, which triggers a useEffect hook. In most cases, you could instead have your event handler directly trigger your side-effect code. Adding useEffect into the mix is a huge point of failure because, well, it sucks. Until you get that chain of deps just right it's not going to run when you think it is, or it's going to run with some stale values.
- localghost3000 4y ago> I would say useEffect is not an escape hatch, it's a fundamental building block of the hooks paradigm The react docs literally call it an escape hatch [0]. First sentence. [0]https://beta.reactjs.org/learn/you-might-not-need-an-effect https://beta.reactjs.org/learn/you-might-not-need-an-effect
- ojkelly 4y agoYep, and escape hatch is actually a great descriptor. useEffect let’s you safely communicate with the world outside react (ie cause side effects). It’s the only reliable way to …escape.
- phailhaus 4y agoThat's funny, they're such a necessary tool for making anything more than simple UI's that I wouldn't consider that an escape hatch. Kind of like saying that screwdrivers are an "escape hatch" for hammers.
- rhaway84773 4y agoThese are the new Beta docs. The original docs made no such claim. Which brings us back to the biggest problem with useEffect. Even the react devs don’t seem to have a clue how it should actually used, until only recently, despite it being among the 2 most used hooks ever since hooks were introduced.
- localghost3000 4y agoWhat about any of that invalidates my assertion that useEffect is not the tool to reach for most of the time? The original docs are outdated The abstraction itself is ripe for misuse Tons of devs use it when they shouldn’t. Insert shrug emoji here.
- lozenge 4y agoTo make it concrete, I think they're saying, if state "rows" depends on state "filter" and "sortOrder", people write `useEffect(() =>setRows(...), [filter, sortOrder])`. Ie writing reactive code but relying on the React render loop to trigger reactions. The problem is that you can no longer step through your code in full and as you say, your code now mandates flushes to the DOM that are unnecessary (mid computation). It's better to setRows at explicit places or learn and use a library like rxjs if you really need to encapsulate that complexity.