Movatterモバイル変換


[0]ホーム

URL:


Mark's Dev Blog

Random musings on React, Redux, and more, by Redux maintainer Mark "acemarke" Erikson
 Sponsor @markerikson
 Home

Blogged Answers: Thoughts on React Hooks, Redux, and Separation of Concerns

Posted on
#javascript#react#redux#hooks#tradeoffs#greatest-hits

This is a post in theBlogged Answers series.


Some observations on the tradeoffs involved in using React hooks

Intro 🔗︎

I've seen a lot of questions about React hooks usage lately, and React-Redux hooks specifically. The most common questions are things like:

I actually have a lot of thoughts on the tradeoffs that hooks bring. Earlier today, Iwrote up a long Twitter thread with some of those thoughts, and I'd like to expand on that thread here.

Before I go further, some caveats. I have written some small example apps that use hooks, but I haven't used them seriously in a real-world app yet. Same goes for ournew React-Redux hooks API in particular - I drove the effort to design and publish those APIs, but I've only briefly used them in action myself. I'm also not an expert on testing, either. I know plenty of theory, I just haven't actually written all that many tests myself (unit or integration). So, I will freely say up front that these are just some opinions and observations, I could easily be wrong, and you should make up your own mind on things.

Hooks, HOCs, and Tradeoffs 🔗︎

Since the minute they were announced, the React community has gone crazy over hooks. While there's been plenty of justified skepticism, large swathes of the community have jumped all-in on hooks, touting them as the "obvious way" to write React code going forward. As is usually the case, the flash and excitement should be tempered with some more realistic expectations.

In one sense, hooks don't give you anything new. Class components have always had state and side effects. Hooks "just" let you do the same thing in function components. In that sense, nothing has changed.

At the same time, hooks change things dramatically. Logic that was split across multiple lifecycles is now co-located. Hooks require use and knowledge of closures instead ofthis. Same results, but written quite differently. In particular, use of closures results in components that are much larger, because you have to write functions inline to capture variables from the scope.

As with any technique, this has tradeoffs. Colocation is generally good, but complex components can be very long. Some of that size can be alleviated by extracting custom hooks. (I guess you could do something similar with defining functions inline - have some factory likemakeClickHandler(a,b, c) to move the actual code outside the component, but that starts to get kind of silly and over-abstracted.)

Because of this, hooks deliberately make different tradeoffs on the "separation of concerns" and "simplicity" spectrums than HOCs do:

In that sense, hooks deliberately lead away from "separation of concerns". A component now explicitly expects to read its own data from somewhereand render it. You could write separate components for fetching and rendering, but now you've reinvented the HOC.

React-Redux Hooks Usage Patterns 🔗︎

The Redux team has always promoted"keeping components unaware of Redux":

They should simply receive data and functions as props, just like any other React component. This ultimately makes it easier to test and reuse your own components.

Now, it's not like our new hooks API completely changes things. We've always encouraged use of selector functions for extracting values from the store state -useSelector() just formalizes it a bit (and you could even reuse your existingmapState functions withuseSelector(), assuming you either memoize the result or useshallowEqual as the comparison function).

Meanwhile, you've always been able to just doconnect()(MyComponent), do some async logic in the component, and then explicitlythis.props.dispatch(someAction). However,we've discouraged that on the grounds that it makes the async code less reusable.:

In general, Redux suggests that code with side effects should be part of the action creation process. While that logic can be performed inside of a UI component, it generally makes sense to extract that logic into a reusable function so that the same logic can be called from multiple places—in other words, an action creator function.

That's part ofwhy action creators, thunks, andmapDispatch exist: to enable dispatching without explicit mention ofdispatch at the call site, and to enable generic "presentational" components.

With our React-Redux hooks, though, you'veonly gotuseDispatch(). So, youalways have that directly available. I can see folks potentially dropping thunks going forward, writing async logic in auseEffect(), and dispatching directly in the component. It may also make it easier to mix together React and Redux in some new ways by extracting custom hooks, as seen inthis example of converting fromconnect() to hooks.

(As a side note: the whole "container/presentational" thing has always been over-interpreted by the community. Dan has sincemostly disavowed his original post, andwhen we revamp the Redux docs, we'll rewrite the"React Usage" tutorials page to stop emphasizing that concept.)

So yes, our React-Redux hooks definitely couple the component more tightly to Redux, because that's basically true for any component that is using context rather than props. There's an implicit dependency on that context instance and the data being provided.

Conclusions 🔗︎

As with most of programming: it's not that either of these approaches is right or wrong. It's that these approaches have different tradeoffs, and each team is going to have to make their own decisions as to which tradeoffs are more important for them.

How much do you want to separate concerns? If you like "shallow" testing components, hooks may not be for you, as they really require "integration"-type tests. Do you prefer cleaner component trees, colocation, and easier static typing, or more separation and indirection?

Long-term, it's going to be interesting seeing the ramifications of this play out in the ecosystem. Hooks have only been out for a few months, so the community is still trying to work out how to best make use of them. It took us years to go from "mixins" to "HOCs", and then even figure out that "render props" were a thing. We'll be exploring hooks usage patterns for a long time.

One other thought: I've frequently observed thatReact and Redux users can be broadly grouped into two points of view: "app-centric" vs "component-centric" design. I think the questions around hooks tradeoffs tie into some of those mindset aspects. Is React your actual "app"? Or is it "just" the UI layer, with the real app being the logic and data kept outside the component tree? Both are very valid viewpoints, again with differing tradeoffs.

Further Info 🔗︎

Also seemy ReactBoston 2019 talk on "Hooks, HOCs, and Tradeoffs", which discusses this topic further.


This is a post in theBlogged Answers series.Other posts in this series:

Recent Posts

Presentations: The State of React and the Community in 2025The State of React and the Community in 2025Presentations: Maintaining a Library and a CommunityReact Advanced 2024: Designing Effective DocumentationReact Summit 2024: Why Use Redux Today?

Top Tags

63 redux56 javascript49 react31 presentation30 greatest-hits

Greatest Hits

Greatest Hits: The Most Popular and Most Useful Posts I've WrittenRedux - Not Dead Yet!Why React Context is Not a "State Management" Tool (and Doesn't Replace Redux)A (Mostly) Complete Guide to React Rendering BehaviorPresentations: Modern Redux with Redux ToolkitWhen (and when not) to reach for ReduxThe Tao of Redux, Part 1 - Implementation and IntentThe History and Implementation of React-ReduxThoughts on React Hooks, Redux, and Separation of ConcernsReact Boston 2019: Hooks HOCs, and TradeoffsUsing Git for Version Control Effectively

Series

21 Blogged Answers4 Codebase Conversion4 Coding Career Advice2 Declaratively Rendering Earth In 3d5 How Web Apps Work8 Idiomatic Redux6 Newsletter13 Practical Redux32 Presentations5 Site Administrivia

[8]ページ先頭

©2009-2025 Movatter.jp