open-source-labs / Swell

Swell: API development tool that enables developers to test endpoints served over streaming technologies including Server-Sent Events (SSE), WebSockets, HTTP2, GraphQL, gRPC, and tRPC..
http://www.getswell.io
MIT License
979 stars 141 forks source link

Wrapping up state management revamp #344

Closed Parkreiner closed 1 year ago

Parkreiner commented 1 year ago

Hi, y'all! Talked about this with some of the OSLabs people earlier today, but wanted to document exactly what I had in mind. If at all possible, I'd like to push an update in the next couple of days to resolve all of these issues. This work started in July of last year, and I think things are the stage where they can quickly be wrapped up for good.

What I'd like changed

I'd like for the state management to be finalized, updating how the entire application is able to access the central store, while pushing for increased type-safety application-wide.

More detailed explanation

One of the main pain points with the Redux Toolkit implementation is that several components have been consuming RTK's built-in useSelector hook. This works just fine at runtime – the entire Redux store will always be passed down from the root Context provider, which the useSelector hook can access and set up selective subscriptions for, no problem. The issue, though, is because useSelector is able to work with any arbitrary Redux implementation, it itself has zero type-safety. By default, the store argument accessed through a selector function is of type any.

With the store being so massive, not having any degree of type-safety or auto-complete for the various properties leads to poor discoverability and virtually zero safety nets. One of the solutions so far has been to type each selector's store argument each time useSelector is used, which isn't great, and puts the burden of typing everything properly on the developer.

Proposed solution

My proposed solution would be to disallow access to the raw useSelector directly, instead forcing the team to access it through a fully-typed wrapper hook that would be co-located with the root store.ts file.

The existing components that consume useSelector directly would need to be updated, as would any documentation, to make it clear how to interact with the store going forward.

In addition, now that some of the longer-standing types have had time to solidify and are less prone to changing structure rapidly, I feel like more of the types exposed through the store can be typed more aggressively. Some of the existing types could be expanded to have their known types listed more concretely. In the event that some objects need support for arbitrary properties in addition to what's know at compile-time, those types can be created via Record intersections.

Possible alternatives

I feel like this is fairly clear-cut. I don't think any other solutions make sense, especially with many of these changes being in line with the official recommendations from the RTK documentation.