Replies: 1 comment
-
+1 to all of this. I have used the NGRX state in various professional and personal projects for several years, and this situation constantly vexes me. I've always assumed there was a technical limitation that prevents creating singular nullable top-level entities, but I'm curious what the reason is. Every project I've worked on has a "View Single Record and Make Edits" kind of page. If the object models are complex enough to warrant an NGRX state solution, it feels incredibly low-tech and counter-intuitive to have non-null values such as 0 or -1 to represent a dummy "not loaded yet" initial object. Glad to know it's not just me! |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
I attended the SignalStore workshop at ng-conf 2024, and I found it to be one of the more useful bits of my conference experience. It's an exciting technology emerging at an exciting time for Angular. Contrats!
Problem Statement
Our small team has been experimenting with using the SignalStore in one of our applications. In some of the earlier experiments, we were working with a collection of entities. In that case, we were able to use the
withEntities
feature of the store, and found an intuitive, maintainable, and scalable API was exposed for working with our state.Building on that success, we're now experimenting with using
@ngrx/signals
in some other portions of our application. The page we're experimenting with now is a large object for a "detail" page, not a collection of entities. The data for the page is not fetched until the user has landed on this detail page. Users can be linked to this page from many different sections of the larger application.Given the asynchronous nature of the data, it feels like it would be beneficial to represent the absence of data in our application's types. When using an
rxjs
BehaviorSubject
, we've often defined our type asBehaviorSubject<Entity | null>(null)
. The intent is to communicate via the type system that the data is not always present, so guard your views appropriately. IMO, this is one of the benefits of strong typing.When trying to carry that concept over to our signal store usage, we're finding things don't necessarily meet our expectations. Many of the examples I have encountered that are similar to our situation tend to use initial state to satisfy strong typing. For example, you may have a type and initial state like this example:
On the surface, this seems to provide the expected developer experience with the signal store. However, I feel like the empty strings and meaningful ID of 0 are footguns. These properties will present as type
string
in TypeScript, when arguablystring | null | undefined
is a better representation. This could lead to an undocumented need for "truthy" checks on our properties. As another solution, we have experimented with setting up nullable types in ourState
, like so:While I feel this better models our data flow in the type system, it has the effect of eliminating the
DeepSignal
-ness of our object. For example:Example
Here's an example repository I've put together. Hopefully it helps to communicate what we're trying to accomplish with the SignalStore, and some of the pain points we've encountered. While the example focuses on a User object, we are looking at the SignalStore for use with domain-specific entity management:
https://github.com/vitale232/signal-store-play/
Discussion
I have a few questions for discussion:
NonNullableUserStore
in the example, and try to use other features likewithRequestStatus
to guard views and account for missing data?I'm curious what others are doing to address these concerns, or if they are even valid!
Beta Was this translation helpful? Give feedback.
All reactions