Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

React-Redux Roadmap: version 8.x, React 18, and TypeScript #1740

Closed
markerikson opened this issue Jun 25, 2021 · 21 comments
Closed

React-Redux Roadmap: version 8.x, React 18, and TypeScript #1740

markerikson opened this issue Jun 25, 2021 · 21 comments
Milestone

Comments

@markerikson
Copy link
Contributor

markerikson commented Jun 25, 2021

I want to start sketching out the likely direction for React-Redux version 8. (I'll refer to it as "v8" for shorthand - please note that I'm referring to our next major version, and not the JS engine :) )

Unlike our giant v7 effort captured in the v7 roadmap issue and the many v7.1 hooks issues, I expect that v8 will be simpler in terms of conceptual changes and design work. On the other hand, it's also possible it might end up involving a significant amount of total effort.

For now, I just want to list what I think are the big-ticket items for a v8 major version.

Planned Major Changes

React 18 and Concurrent Compatibility

We have numerous prior threads discussing how React-Redux will work with React's eventual Concurrent features. A lot of that has involved speculation and hypotheticals because of the long drawn-out development process for Suspense and Concurrent React. Now that React 18 alpha has been announced, it looks like A) the new behaviors are finally about to become reality, B) we have some more concrete ideas of what APIs exist and what the potential issues are, and C) the React team is trying to share info and prepare the ecosystem over in the React 18 Working Group.

While we don't have a final concrete plan for what will happen, most likely React-Redux v8 will:

  • Keep the exact same primary public APIs we have now (useSelector and connect)
  • Update the internals to be built around useMutableSource as an integration layer to provide better compatibility with Concurrent rendering. (It's also possible that we could look at context-based approaches again if React finalizes a "context selectors" API and makes that available.)

TypeScript

The three major Redux libraries have all followed different paths for TS usage and development:

  • The Redux core is plain JS, with TS typedefs maintained in the repo
  • React-Redux is plain JS, but with the typedefs maintained by the community in DefinitelyTyped
  • Redux Toolkit is entirely written in TS

We do have a still-unreleased conversion of the Redux core lib sitting in its master branch. It's been there for a while, and tbh we still don't have specific plans to release that any time soon. There's a bunch of factors around ecosystem compat and churn we'd need to consider first.

The React-Redux typedefs are incredibly complex, and I'd like to give kudos to everyone who's built them up over the years. In particular, the handling of the various connect overloads is really complicated, which isn't surprising when you consider the number of optional parameters and overloads it has.

But, if we're going to be doing a major version, we ought to go ahead and rewrite the React-Redux source in TS, so that we can stop having to deal with separate typedefs.

Code Cleanup

The primary breaking change here will be the planned removal of the connectAdvanced API. It was part of the original v5 implementation, largely because the author of v5 wanted more flexibility than the existing connect API offered. A few other folks used it, but ultimately it saw very little use. In addition, our hooks API has effectively addressed those use cases.

We announced it would be deprecated a couple years ago. While we never formally slapped a // @deprecated tag on it, the description's been there for a while. Consolidating the logic for connect and connectAdvanced will probably simplify things a bit.

We'll see what else we can clean up in the process.

Other Changes?

I don't immediately have anything else specific intended for v8 off the top of my head. I still like the idea of some Proxy-based selector handling ala #1653 , but it seems like that should be addressed more as a general Redux usage thing than building something directly into React-Redux

Timeline

No idea! :)

Okay, so we're sorta inching towards that now. I'm participating in the React 18 Working Group discussions, and they've emphasized that they want to help the ecosystem improve compat leading up to a live React 18 release. So, this is coming, but no hard dates.

Meanwhile, I've requested help from the community in migrating the current codebase to TS, as a foundation before we do any attempted compat changes - that way we're not trying to tackle both at once.

So, I could at least foresee that we might be trying to pull something together fully near the end of 2021, maybe early into next year, but this is also largely dependent on the React team's own timeline for React 18.

Requests for Help

As always, we welcome anyone who'd like to help contribute! The biggest immediate needs are:

React 18 alpha compat testing

We've already got an issue at #1732 asking people to try out React-Redux v7 with the React 18 alphas, and try to come up with actual examples of bugs and places where things break. That would give us things to try testing against as we work on Concurrent compat.

Related to this, Daishi Kato has put together a testbed that checks whether libraries potentially get along with Concurrent rendering, at https://github.com/dai-shi/will-this-react-global-state-work-in-concurrent-rendering . That will likely be a useful starting point.

If folks really want to dig in, I know that there's been a couple experiments with trying to modify React-Redux to use useMutableSource already, and it would be interesting to see some PRs to get an idea of how much code churn that involves.

We're also going to want to freshen up the https://github.com/reduxjs/react-redux-benchmarks repo so that we can do perf benchmarks on new versions.

Finally, both the benchmarks repo and our tests will need updating to actually use React 18's new APIs, and we'll need new test scenarios that leverage those to have meaningful behavior checks.

TypeScript Conversion

Per #1737 , we've got the first couple steps going on porting the codebase to TS (just some first build tweaks so far). We'd love to have more folks get involved here, especially since we maintainers don't have time to seriously work on that part right now.

@markerikson markerikson pinned this issue Jun 25, 2021
@timdorr
Copy link
Member

timdorr commented Jun 25, 2021

Are we wanting to make v8 only support React 18 or do we want to try for backwards compat? I'm fine with making a hard cutover and continuing to support 7.x as long as there are bug fixes (like we've done with 5.x and 4.x in the past). I'm not even sure if there's a BC path for useMutableSource being planned, is there?

@markerikson
Copy link
Contributor Author

Yeah, that's a great point. Using either useMutableSource or context selectors means a hard requirement on React 18.x , in the same way that React-Redux v7 has a hard requirement on React 16.8+.

So, yes, we'll need to maintain v7 for use with React 16/17. Fortunately, v7 is very stable at this point and I don't expect much if any future work will be needed on it.

@markerikson
Copy link
Contributor Author

Some other points to consider: what about file formats in our published package?

If you look at the current output ( https://unpkg.com/browse/react-redux@7.2.4/ ), we've got these formats:

  • /dist
    • react-redux.js: UMD dev
    • react-redux.min.js: UMD prod
  • /es:
    • Individual files, ES modules, ES5 syntax, embedded process.env.NODE_ENV checks still inside
  • /lib:
    • Individual files, CommonJS modules, ES5 syntax, embedded process.env.NODE_ENV checks still inside

The Redux core is a similar setup.

Meanwhile, for RTK ( https://unpkg.com/browse/@reduxjs/toolkit@1.6.0/dist/ ), we've got a totally different setup:

There's also the question of adding an exports keyword to package.json, which I've been told is a breaking change due to how Node supports ESM.

So, some questions:

  • Should we be delivering build formats as individual files on disk, or one bundle per format? How does this affect tree-shaking?
  • Should we still have a UMD build or a CommonJS build?
  • If we do keep UMD builds, is it okay to change the filenames to something like dist/react-redux.umd.js?
  • Should we stop delivering ES5 syntax and target, say, ES2017? (I don't think this one will make much of a difference in our case - almost everything is simple functions, and looking through some of the build output, at most I think I see some destructuring that would be a bit shorter)

@markerikson
Copy link
Contributor Author

Update: just had a good conversation with the React team, and the one-line summary is that they're going to rework useMutableSource to provide better support for more use cases for Redux and other libraries. They're also going to publish a "shim" package so that it can work with both React 17 and 18, similar to the one they published for lifecycles a while back.

This should hopefully pave the way for a fairly smooth migration path for React-Redux itself, and allow us to keep the same public-facing API so that our end users can update with minimal changes needed.

Some notes on the discussion are here:

reactwg/react-18#84 (comment)

@markerikson
Copy link
Contributor Author

I'd originally planned that v8 would have a hard dependency on React 18, even though the useSyncExternalStore shim works all the way back to React 16.9, and as of https://github.com/reduxjs/react-redux/releases/tag/v8.0.0-alpha.1 I dropped use of the shim. This is partly to save the size of the shim itself (which looks to be about 750b), and also because it seemed like it would simplify things overall.

Earlier today someone suggested that we could try adding a 'react-redux/compat' entry point that would use the shim. I think this is doable. We're already doing basically the same thing with 'react-redux/alternate-renderers', which changes what batching technique is used to support non-ReactDOM/RN renderers. We could do the same with uSES as well.

This would also have the benefit of keeping React-Redux potentially working with Preact, since I don't think they've tried to implement uSES at all.

@rememberlenny
Copy link

Now that React 18 is GA, should updates to using concurrent features be expected?

@markerikson
Copy link
Contributor Author

markerikson commented Mar 29, 2022

Not sure what you mean by "updates to using concurrent features" - can you clarify?

FWIW I think that the current 8.0-beta release is basically feature-complete. However, I haven't had time to test out any of the SSR functionality I added, and I'd really like some assistance trying that out before I publish this as final.

Ideally I'd like to publish v8 live within the next couple weeks, but it depends on how much time I can put into it and if there's any other tweaks that need to be made.

There were some suggested SSR examples linked over in the PR that would make potential starting points:

@markerikson
Copy link
Contributor Author

Still not 100% sure I understand what's being asked :)

I would certainly expect parts of the React community to begin updating to React 18, and then start using features like useTransition, yes. That's a large part of the new release.

But I'm not sure I follow how that ties into this thread specifically.

@markerikson
Copy link
Contributor Author

So there's a couple complications this morning.

Turns out that creating a new CRA project with a Redux template is now failing, because CRA tries to install the latest React as a default, and NPM now force-installs peer deps and throws errors if it can't match. So, it installs React 18, then tries React-Redux v7, sees that v7 only supports React 17, and errors.

This unfortunately brings up several issues, though.

  • We really don't want people using React-Redux v7 with React 18. It'll run, and tbh most people probably won't see any problems, but the point of v8 is to make it concurrent safe. I guess I can do a patch release that bumps the peer dep, but it feels misleading.
  • My plan for a while now has been to have v8 work with 18 only. Part of that is to avoid the extra 1K bundle size from the use-sync-external-store shim package. I did add a "react-redux/compat" entry point that falls back to the shim. However... I just realized that this is going to cause problems with React Native, because they don't get 18 support for a while :( so if I push v8 out the door as 18-only, that's probably going to cause RN projects to break. I'm starting to wonder if I may have to make v8 use the shim by default. The upside is it then supports back to 16.8, but that locks us in to using the shim for the rest of 8.x because removing it would be breaking and thus a major. Bleh.

I've pinged the React team to see if they have thoughts, and will try to sort this out shortly.

@markerikson
Copy link
Contributor Author

I've put out React-Redux 7.2.7 as a stopgap, which bumps the peer dep to include react@^18. But, the real answer is we need to finalize v8.

@markerikson
Copy link
Contributor Author

Talked about this with the React team today, and they advised to go ahead and use the shim by default. So, in the next couple days I'm going to ship a new React-Redux v8 beta that flips the current setup:

  • The primary entry point will depend on the useSyncExternalStore shim
  • There will be some alternate entry point that directly imports useSyncExternalStore from React (entry point name TBD, suggestions welcome!)

This has a few implications:

  • React-Redux v8 will now work with React 16.8 and higher by default, rather than hard-requiring React 18
  • Users will be able to upgrade to React-Redux v8 immediately, even if they have no plans to update to React 18 any time soon
  • v8 will also continue to work with React Native apps even though the "new RN architecture" and React 18 support isn't out yet
  • The shim will add about 1K min to the bundle size. However, useSelector itself did get smaller because we ripped out its own subscription logic. (I'll try to do a comparison and see how much the final size changes.) We'll offer a suggestion that people can alias the "direct import" entry point instead if they want to strip out the extra size in their own apps.

@markerikson
Copy link
Contributor Author

8.0.0-beta.4 is available with the change to use the shim by default:

https://github.com/reduxjs/react-redux/releases/tag/v8.0.0-beta.4

@TheHolyWaffle
Copy link

TheHolyWaffle commented Apr 11, 2022

According to https://github.com/dai-shi/will-this-react-global-state-work-in-concurrent-rendering, there seems to be a few use cases with react-redux ^8.0.0-beta.3 not working yet in react 18

@dai-shi
Copy link
Contributor

dai-shi commented Apr 11, 2022

(And, it's totally expected.)

@markerikson
Copy link
Contributor Author

@TheHolyWaffle That's expected, really.

Per reactwg/react-18#70 , libraries with external mutable stores are not expected to have "full 100% absolute perfect" compat with Concurrent rendering, even with useSyncExternalStore being used.

Additionally, as much as @dai-shi has done amazing work on that benchmark, Andrew pointed out at #1808 (comment) that the benchmark's capabilities are somewhat limited anyway.

So, switching over to use useSyncExternalStore in v8 is all that we can do on our end.

@markerikson
Copy link
Contributor Author

React-Redux v8 is out, so I think we can call this done :)

@geekact
Copy link

geekact commented May 24, 2022

Should batch be removed from entry file since it's useless at React18 ?

@markerikson
Copy link
Contributor Author

@geekact : no, because React-Redux v8 can still be used with React 16 and 17, which do not have automatic batching.

@tkforce
Copy link

tkforce commented Oct 27, 2023

Not sure what you mean by "updates to using concurrent features" - can you clarify?

FWIW I think that the current 8.0-beta release is basically feature-complete. However, I haven't had time to test out any of the SSR functionality I added, and I'd really like some assistance trying that out before I publish this as final.

Ideally I'd like to publish v8 live within the next couple weeks, but it depends on how much time I can put into it and if there's any other tweaks that need to be made.

There were some suggested SSR examples linked over in the PR that would make potential starting points:

Hi @markerikson,

Do you mean with React-Redux v8, we can now utilize useTransition or startTransition to prioritize state updates?

startTransition(() => {
   dispatch(someAction)
})

@markerikson
Copy link
Contributor Author

@tkforce : I"m honestly still hazy on transitions, but my understanding is that external state libraries that use useSyncExternalStore don't benefit from that. (I could be wrong, and would appreciate some examples proving that either way.)

@dai-shi
Copy link
Contributor

dai-shi commented Oct 28, 2023

Just wrote a blog post: https://blog.axlight.com/posts/why-use-sync-external-store-is-not-used-in-jotai/
It has some codesandbox examples that people can play with.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants