ngrx / platform

Reactive State for Angular
https://ngrx.io
Other
7.99k stars 1.96k forks source link

provideState cannot be used in standalone components #4234

Closed wshager closed 6 months ago

wshager commented 6 months ago

Which @ngrx/* package(s) are the source of the bug?

store

Minimal reproduction of the bug/regression with instructions

@Component({
  // ...
  providers: [provideState({})]
})
// ...

Typescript compilation error: Type 'EnvironmentProviders' is not assignable to type 'Provider'

Expected behavior

No compilation error

Versions of NgRx, Angular, Node, affected browser(s) and operating system(s)

Ngrx: 15.3, Angular: 15.2.9, Node: 20.2

Other information

No response

I would be willing to submit a PR to fix this issue

brandonroberts commented 6 months ago

This is by design in Angular. You either have to use them at the application bootstrap level, or the route providers level. We use the ENVIRONMENT_INITIALIZER token from Angular to register the feature state. No such initializer is available in the component providers.

wshager commented 6 months ago

@brandonroberts A workaround is to import the feature state in an NgModule and import that module in the standalone component. That gave me the impression that there should be a simpler way.

BenGrn commented 4 months ago

@brandonroberts A workaround is to import the feature state in an NgModule and import that module in the standalone component. That gave me the impression that there should be a simpler way.

@wshager Did this work within a standalone application or a module based one utilising standalone components only?

hudzenko commented 1 month ago

Hi, we are currently using this workaround with module import as well. Unfortunately..

The case: We have separate lazy loaded widgets which are represented as standalone components. Each component has some feature store and imports some shared feature stores and has no it's own route (as it not a page but a widget). Providing feature stores globally does not suits us as well because of lazy loading.

So it is really a problem that it is impossible to provide a feature store to a standalone component with no route.

We have also found some tricky workaround with createEnvironmentInjector, but not sure it is a good solution.

PS. Component store does not suits our needs because we have some shared feature stores (which unfortunately can not be moved to root lvl due to lazy loading requirement).

rainerhahnekamp commented 1 month ago

@hudzenko I guess the only solution is to fallback to the component or the signal store. What speaks against having shared feature states with the global store (provideState) and using the component/signal store for your widgets?

hudzenko commented 1 month ago

@rainerhahnekamp Thanks for the answer!

The main issue is that we can not currently find a good place to register shared feature stores. We are trying to not to add them to "application bootstrap level" (to keep our specific feature like fully lazy loaded) and at the same time our components does not have any other single entry point (like a single specific route or let's say micro-frontend).

That is why we have a not really good workaround (but it works as ngrx does not register same state or effects twice): We import same FeatureStoreModule to different widget-components or route-components.

Well yeah, ideally is to move the shared things to global store (to the root lvl as there is no other shared entry point). And convert not shared state logic to components or signal store. But we need to negotiate making some of our logic as not lazy loaded :)

rainerhahnekamp commented 1 month ago

and at the same time our components does not have any other single entry point

Ouch. That doesn't make it easier.

Have you considered moving your shared feature state to ngrx signals/component store? You have simple services, could provide them in root, and as long as no one calls that service, it will not activate itself.

Although I'm afraid that the service files will end up in the main bundle, that would probably be the easiest solution.

wshager commented 1 month ago

Imho the whole point of state management is to have a single shared state that gets accumulated over time. Any other setup would negate the use case, because you would not be able to access the shared state, as far as I can understand. Thanks for the suggestions, but I'm still hoping for a more ergonomic solution.

Op do 27 jun 2024 13:08 schreef Rainer Hahnekamp @.***>:

and at the same time our components does not have any other single entry point

Ouch. That doesn't make it easier.

Have you considered moving your shared feature state to ngrx signals/component store? You have simple services, could provide them in root, and as long as no one calls that service, it will not activate itself.

Although I'm afraid that the service files will end up in the main bundle, that would probably be the easiest solution.

— Reply to this email directly, view it on GitHub https://github.com/ngrx/platform/issues/4234#issuecomment-2194402291, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAFBLMGYBXLOI7V6MZE27X3ZJPXCZAVCNFSM6AAAAABC4NWSOWVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDCOJUGQYDEMRZGE . You are receiving this because you were mentioned.Message ID: @.***>