I've completely stopped using class components after spending some time with Hooks in a small-to-mid-sized application.
The big wins for me were:
- passing an empty array as the last argument of useEffect makes useEffect work in a similar fashion to the old ComponentDidMount. You can have any number of useEffect invocations in a component, and for a component that is, say, loading data from two different sources, I find having two discrete useEffects loading just what they need much more clean/intentional than putting everything into a single lifecycle method.
- using Hooks with Context almost completely fills the giant state management hole that has been (imo) hampering React since its inception. Hooks + Context is a cleaner and more comprehensible solution than React + Redux for any application that has a reasonable amount of state complexity. For data-heavy applications, Redux may still be a good choice, but for everything else, the Hooks + Context combination is hard to beat.
How do you handle the drawback that changing the context will rerender all components that use the context? Putting too much state into a single context does seem like it could cause performance issues, especially with state that changes often.
I agree that if you had a large (in the dozens, if not hundreds) number of dependent components, it could be an issue. However, I've noticed no performance degradation with my usage -- I use a top-level AuthContext component to handle user data/login state, and another for access/caching of the app's main data.
In a single view (for lack of a better term), I'd guess the largest number of components that access either context is six.
Can you elaborate a bit about Context? I've been curious but wrapping multiple context layers to get multiple values feels awkward and wrapping an object to get CD around that feels like it screws over React rerendering logic.
Sure. The app I'd been working on had previously been using the original 'render prop' style of accessing context in functional components and using the this.contextType accessor for class-based components. Both approaches had their downsides:
- 'render props' are fairly awkward to write, and add a lot of noise to a component that's working with data from multiple contexts.
- this.contextType can only give a component access to one context. This is a pretty big problem.
With Hooks, useContext lets you reference and destructure contexts in a really elegant way. Say you want to show a user's name if they're logged in, with the render prop approach it's something like:
I find class components easier to visually parse and understand because of the organization of lifecycle methods into separate functions. I do understand the benefit of hooks, but I still reach for class components when working on something new because I'm extremely productive with them.
I agree with you that the class components are bit easier to visualize the flow than hooks.
At first, React hooks look simple and easy. But when i started thinking about setTimeout's, API calls, Re-renders, the flow get's difficult to imagine.
I switched over to hooks completely. Its just way faster to write and useContext, useState, useReducer, etc are great easy ways to structure my app. Working with useRef took some getting used to but now that I am used to it I would not go back
I haven't tried using them yet but hey do look like they remove a lot of boilerplate code from component. Kind of what redux did to state when we had to manually manage state in components.
I've started to think in hooks which is good. Not that it is always clear, but seen as a way to connect function and presentation, hooks work well. At times I question the directionality of hooks - do they hook function to presentation, presentation to function or both? The useEffect hook appears to be a case of presentation => function whereas many others are the opposite, and that can make it more problematic, as others have pointed out.
I'm not sure this a valid understanding, but it works for me as a heuristic.
I am starting to use hooks and it is actually way better to do async thunk axios http calls than to put it in a lifecycle method. the code is more succinct and clear and you don't have to keep the lifecycle in mind as much
The big wins for me were:
- passing an empty array as the last argument of useEffect makes useEffect work in a similar fashion to the old ComponentDidMount. You can have any number of useEffect invocations in a component, and for a component that is, say, loading data from two different sources, I find having two discrete useEffects loading just what they need much more clean/intentional than putting everything into a single lifecycle method.
- using Hooks with Context almost completely fills the giant state management hole that has been (imo) hampering React since its inception. Hooks + Context is a cleaner and more comprehensible solution than React + Redux for any application that has a reasonable amount of state complexity. For data-heavy applications, Redux may still be a good choice, but for everything else, the Hooks + Context combination is hard to beat.