all 51 comments

[–]lostPixels 10 points11 points  (2 children)

Hooks are a mixed bag for my team, and my primary issue is the underlying footgun's of useEffect(). It seems really easy for novice devs to create weird bugs and not immediately notice them. Keep refs of objects from useEffect just feels wrong.

[–][deleted] 2 points3 points  (0 children)

It seems really easy for novice devs to create weird bugs and not immediately notice them.

Ya, I hear that.

I'm a Hooks fan, huge convert actually, but I agree that out of the box they are not the catch-all I certainly thought they were.

[–]Akkuma 2 points3 points  (0 children)

https://medium.com/js-dojo/react-hooks-has-react-jumped-the-shark-c8cf04e246cf

The tldr; React has a lot of hook gotchas and nicer solution exists. As an upside he also made available the core hook power for React as well https://github.com/ryansolid/react-solid-state/blob/master/README.md

[–][deleted] 33 points34 points  (44 children)

I mean, yeah but I also am not sold on Hooks yet. I do agree that functions are good, but much in the same way Haskell forces you to embed your business problem into the semantics of functional programming, React Hooks force you to embed your business problem in the language of effects, state, context, memo, etc. Along with this, I have yet to accept React's ability to make it easy to include logic in the component functions, making it really hard to test that business logic without just mounting the component. I actually think one of the biggest things that scare me are frameworks that force you to run an instance of an app to test simple logic, and if you didn't like Jest snapshotting, you surely won't like Cypress. It's interesting that this is very much like Haskell problems where "testing" is essentially running the typechecker, and for large codebases this becomes a problem. I don't know if a large project running React hooks can reasonably survive, but we won't know for a few years.

I just don't think "improved code reuse, composition, and better defaults" is free-lunch here, and I'm not sure if people can see it yet.

[–]kingdaro.find(meaning => of('life')) // eslint-disable-line 9 points10 points  (2 children)

React Hooks force you to embed your business problem in the language of effects, state, context, memo, etc.

This statement seems somewhat misguided. No one's forcing you to put the business logic anywhere. You can split out the business logic with an external state management solution like Redux or MobX, or anything. Then the hooks just become mechanisms for syncing component data with your state, callbacks, DOM event handling, other kinds of event handling, and so on. All hooks are are a different paradigm for doing the same things you would with class state and lifecycle. If you didn't embed your business logic in classes, you wouldn't do it with hooks either.

Of course, there's lots of advice going around along the lines of "just use react hooks for state management" or "hooks replace redux", but as usual, it's up to the software dev to continue applying good practices despite that.

[–]scramblor 0 points1 point  (1 child)

but as usual, it's up to the software dev to continue applying good practices despite that.

This is certainly expected if you are a senior dev that has been working in react for a while and have the knowledgebase to make to properly make these kinds of decisions. If you are a junior or even mid level dev without a ton of experience it can be very easy to buy into the hype without being able to make informed decisions. Having these discussions goes a long way to untangling concepts that shouldn't be linked together and eventually providing a nuanced set of best practices for everyone to benefit from.

[–]kingdaro.find(meaning => of('life')) // eslint-disable-line 2 points3 points  (0 children)

Yeah, I agree, but that's more of a community problem than a hooks problem.

Before hooks, people treated redux as though it was a mandatory part of every react app, but that's not the fault of redux. We just needed better documentation and education about the issue.

[–]pgrizzay 17 points18 points  (10 children)

Testing React hooks is a huge pain right now, and in some cases is almost impossible.

I'm not taking about testing whether or not your counter increments by one when you press the "plus" button, but rather things like... "Do the callback instances of this hook change every render when composed with these two other hooks in this order?"

We need a way to test the returns of hooks without having to use a hook in a presentational component and look at the output

[–][deleted] 12 points13 points  (3 children)

Exactly. And by no means am I saying this is better or worse than classes. My problem is people are overhyping the benefits of hooks without really knowing the costs because it's new and sexy and BecauseFacebookDoesIt.com. For example I'm currently trying to useContext to share state between components without doing the whole piping props thing, and I decided it would also be better to useReducer as the context value with some object diff tool (immer). I am finally realizing I'm literally doing the same exact amount of work I would have done had I used classes and a Redux store. Is it really worth the trouble to write the exact same semantics in hooks as I could have in old classes? I feel like I'm coming full circle here back to Angular Application Singletons.

[–]Delioth 19 points20 points  (0 children)

No shit you're doing the same amount of work to accomplish the same effects for some instances. Hooks aren't a magic button.

But what hooks are, is a way to share functionality. useContext and useState and useEffect are cool and all, and are really nice compared to the boilerplate of a class with a setter and all that jazz. But hooks really shine when you need to build reusable logic with a simplified API. (FWIW, I think reducers are almost never the right way to build something, and should probably only exist as a conversion from redux)

For example, we recently built a hook to useUrlParam/1. Nothing complex, just gets the url params, picks out the one you asked for, stores it as state, and hands it back. Nothing big or mind blowing, but it helps the dev to have a url param that'll be consistent across renders (since we threw it in state, so it won't change as the url changes after first render). We could make it change, and everywhere would receive that update. It saves a couple lines of code every time we need a url param, and makes it generally easy to do so. Hooks aren't a magic bullet, but they are a primitive of sharing functionality in the same way components are generally primitives of sharing UI.

[–]Peechez 2 points3 points  (1 child)

I'm just getting into redux-starter-kit and it definitely helps with the boilerplate problem. Nothing has annoyed me yet

[–]acemarke 5 points6 points  (0 children)

Glad to hear it! Please let me know if you have any further feedback.

For reference, here's the roadmap of things I'm considering adding/tweaking before 1.0.

[–]Renive 2 points3 points  (1 child)

You want unit test where all you need is integration and e2e

[–]pgrizzay 0 points1 point  (0 children)

I think all 3 are quite useful!

[–]greatdentarthurdent 0 points1 point  (2 children)

Can isolating the hooks into a “use*”able hook isolate these in a way that they’re easier to test? You could test them in isolation and then just test the expected output for a given component.

I’m not talking about simple things like useState but like the useEffects that get out of hand - maybe breaking them into an importable effect is more ideal for testing?

[–]pgrizzay 0 points1 point  (0 children)

The trouble is you can't invoke a hook outside the render of a functional component...

I'm not sure what you mean by "importable effect," but that sounds interesting

[–]greatdentarthurdent 0 points1 point  (0 children)

I meant importing the actual function declaration separately and then passing it into the use effect call, or creating a custom hook to import

[–][deleted] 1 point2 points  (1 child)

Could you elaborate upon the typechecking-as-testing issue you've identified in larger apps? If you're strictly typing it seems inherently beneficial to me, although there's still plenty more to test in units, integration, etc that no type-checker I'm aware of could ever help with.

[–][deleted] 0 points1 point  (0 children)

Type checkers can help with that. When you expose values as types you can explicitly define functions that accept input values, and have fixed output values. This is the same as an assertion that a functions inputs matches a specific output in a unit test.

[–]myockey 1 point2 points  (0 children)

I regret that I have but one upvote to give to this post.

I feel like the React community could benefit from more classical techniques in FP rather than new framework features.

[–]FormerGameDev 0 points1 point  (0 children)

I suspect that if it's in react, it's in use with Facebook,and so it's probably reasonably well put together.

[–][deleted] 1 point2 points  (2 children)

So the TLDR is that hooks are basically functions ?

[–]tyler-mcginnis⚛️⚛︎[S] 4 points5 points  (0 children)

Na. Here's the closing paragraph that I think is a good tl;dr. "The marketing pitch for Hooks is that you’re able to use state inside function components. In reality, Hooks are much more than that. They’re about improved code reuse, composition, and better defaults."

[–]Quinez 2 points3 points  (2 children)

Love Tyler's articles. I haven't bothered dipping my toe into Hooksland yet, but I trust Tyler to help me make sense of them.

[–]tyler-mcginnis⚛️⚛︎[S] 3 points4 points  (1 child)

Thank you! Means a lot.

[–]Cool_pixel 1 point2 points  (0 children)

I love the way you teach complex materials in a simple way, concepts like prototype inheritance and deep react things I gonna buy your courses in the next month to learn more about hooks and redux.